From 5655ef500bd915d7e72a33a7ba1609cb96422801 Mon Sep 17 00:00:00 2001 From: Frederic Salmen <4583669+salmenf@users.noreply.github.com> Date: Wed, 1 Jan 2025 17:16:02 +0100 Subject: [PATCH] Code restructuring and refactoring, remove code for desktop --- .github/workflows/build_tauri.yml | 81 - @webwriter/app-desktop/package.json | 16 - @webwriter/app-desktop/src-tauri/Cargo.lock | 4547 ----- @webwriter/app-desktop/src-tauri/Cargo.toml | 31 - @webwriter/app-desktop/src-tauri/Info.plist | 12 - @webwriter/app-desktop/src-tauri/build.rs | 3 - .../app-desktop/src-tauri/entitlements.plist | 10 - @webwriter/app-desktop/src-tauri/src/main.rs | 21 - .../app-desktop/src-tauri/tauri.conf.json | 108 - @webwriter/core/index.html | 2 +- @webwriter/core/lit-localize.json | 6 +- .../core/model/clients/file.test.ts | 0 @webwriter/core/model/clients/file.ts | 208 + @webwriter/core/model/clients/index.ts | 561 +- .../core/model/clients/llm.test.ts | 0 @webwriter/core/model/clients/llm.ts | 526 + .../core/model/clients/pocketbase.test.ts | 0 @webwriter/core/model/clients/pocketbase.ts | 200 + @webwriter/core/model/environment/index.ts | 226 - @webwriter/core/model/environment/tauri.ts | 278 - @webwriter/core/model/index.ts | 4 +- .../core/model/marshal/h5p.test.ts | 0 @webwriter/core/model/marshal/h5p.ts | 5 +- @webwriter/core/model/marshal/html.test.ts | 0 @webwriter/core/model/marshal/html.ts | 11 +- @webwriter/core/model/marshal/index.ts | 2 +- @webwriter/core/model/marshal/ipynb.test.ts | 0 .../core/model/marshal/markdown.test.ts | 0 .../model/marshal/parserserializer.test.ts | 0 .../core/model/marshal/parserserializer.ts | 3 - @webwriter/core/model/marshal/zip.test.ts | 0 @webwriter/core/model/marshal/zip.ts | 4 +- @webwriter/core/model/schemas/account.test.ts | 0 .../model/schemas/{accounts.ts => account.ts} | 36 +- ...ndex.grammar => contentexpression.grammar} | 0 .../model/schemas/contentexpression.test.ts | 0 .../index.ts => contentexpression.ts} | 4 +- .../cssproperty2.grammar => cssvalue.grammar} | 2 +- .../core/model/schemas/cssvalue.test.ts | 0 @webwriter/core/model/schemas/cssvalue.ts | 2052 +++ .../cssspec.ts => cssvaluedefinition.data.ts} | 71 +- ...dex.grammar => cssvaluedefinition.grammar} | 28 +- .../core/model/schemas/cssvaluedefinition.ts | 373 + .../schemas/customelementsmanifest.test.ts | 0 .../customelementsmanifest.ts | 0 @webwriter/core/model/schemas/datatypes.ts | 292 - @webwriter/core/model/schemas/index.ts | 16 +- @webwriter/core/model/schemas/license.test.ts | 0 @webwriter/core/model/schemas/license.ts | 37 + @webwriter/core/model/schemas/locale.test.ts | 0 @webwriter/core/model/schemas/locale.ts | 63 + .../core/model/schemas/mediatype.test.ts | 0 @webwriter/core/model/schemas/mediatype.ts | 79 + @webwriter/core/model/schemas/package.test.ts | 0 .../{packageschema/index.ts => package.ts} | 53 +- .../core/model/schemas/resource/head.test.ts | 0 .../{resourceschema => resource}/head.ts | 0 .../schemas/resource/htmlelementspec.test.ts | 0 .../htmlelementspec.ts | 0 .../core/model/schemas/resource/index.test.ts | 0 .../{resourceschema => resource}/index.ts | 2 +- .../plugins/base.css} | 8 + .../plugins/base.ts | 10 +- .../plugins/canvas.ts | 0 .../plugins/deprecated.ts | 0 .../plugins/form.ts | 0 .../plugins/grammar.ts | 0 .../plugins/heading.ts | 0 .../plugins/index.ts | 0 .../plugins/list.ts | 0 .../plugins/math.ts | 0 .../plugins/media.ts | 2 +- .../plugins/modal.ts | 2 +- .../plugins/phrasing.ts | 0 .../plugins/section.ts | 0 .../plugins/style.ts | 2 +- .../plugins/svg.ts | 0 .../plugins/table.ts | 0 .../plugins/textblock.ts | 4 +- .../plugins/widget.ts | 2 +- .../themes/base.css | 0 .../themes/holiday.css | 0 .../themes/index.ts | 0 .../themes/pico.css | 0 .../themes/sakura.css | 0 .../themes/simple.css | 0 .../themes/water.css | 0 @webwriter/core/model/schemas/semver.test.ts | 0 @webwriter/core/model/schemas/semver.ts | 68 + .../valuedefinition/cssproperty.grammar | 311 - .../model/schemas/valuedefinition/index.ts | 819 - .../core/model/stores/accountstore.test.ts | 0 @webwriter/core/model/stores/accountstore.ts | 34 +- .../core/model/stores/documentstore.test.ts | 0 @webwriter/core/model/stores/documentstore.ts | 64 +- @webwriter/core/model/stores/index.ts | 84 +- .../core/model/stores/packagestore.test.ts | 0 @webwriter/core/model/stores/packagestore.ts | 691 +- .../core/model/stores/rootstore.test.ts | 0 @webwriter/core/model/stores/rootstore.ts | 66 + @webwriter/core/model/stores/uistore.test.ts | 0 @webwriter/core/model/stores/uistore.ts | 1 + @webwriter/core/model/templates/index.ts | 2 +- .../core/model/utility/index.test.ts | 8 +- .../{utility.ts => model/utility/index.ts} | 55 +- @webwriter/core/package.json | 49 +- @webwriter/core/tsconfig.json | 3 +- .../debugoverlay/index.ts} | 21 +- .../core/view/app/editor/editor.test.ts | 0 .../core/view/{ => app}/editor/editor.ts | 51 +- @webwriter/core/view/app/editor/index.ts | 2 + .../core/view/app/editor/nodeviews.test.ts | 0 .../core/view/{ => app}/editor/nodeviews.ts | 18 +- .../editor/prosemirror-view/README.md | 0 .../editor/prosemirror-view/browser.ts | 0 .../editor/prosemirror-view/capturekeys.ts | 0 .../editor/prosemirror-view/clipboard.ts | 2 + .../editor/prosemirror-view/decoration.ts | 3 +- .../{ => app}/editor/prosemirror-view/dom.ts | 0 .../editor/prosemirror-view/domchange.ts | 12 +- .../editor/prosemirror-view/domcoords.ts | 0 .../editor/prosemirror-view/domobserver.ts | 0 .../editor/prosemirror-view/index.ts | 3 + .../editor/prosemirror-view/input.ts | 2 + .../editor/prosemirror-view/selection.ts | 0 .../editor/prosemirror-view/viewdesc.ts | 10 + @webwriter/core/view/app/index.test.ts | 0 @webwriter/core/view/app/index.ts | 481 + .../metaeditor.ts => app/metaeditor/index.ts} | 13 +- .../palette.ts => app/palette/index.ts} | 71 +- .../settings}/accountform.ts | 143 +- .../settings}/accountmanager.ts | 59 +- .../settings}/configurator.ts | 2 +- .../{configurator => app/settings}/index.ts | 33 +- .../settings}/keymapmanager.ts | 5 +- .../settings}/packageform.ts | 8 +- .../toolbox.ts => app/toolbox/index.ts} | 18 +- .../{editor => app/toolbox}/widgetoptions.ts | 2 +- .../assets}/app-icon-transparent.svg | 0 .../core/{ => view/assets}/app-icon.png | Bin .../core/{ => view/assets}/app-icon.svg | 0 .../view}/assets/icons/filled/bolt.svg | 0 .../core/view/configurator/packagemanager.ts | 793 - @webwriter/core/view/editor/index.ts | 11 - .../datainputs/csspropertyinput.test.ts | 26 + .../{ => datainputs}/csspropertyinput.ts | 14 +- .../datainputs/{index.ts => datainput.ts} | 13 +- .../elements/{ => datainputs}/fileinput.ts | 2 +- .../view/elements/datainputs/languageinput.ts | 10 +- .../view/elements/datainputs/licenseinput.ts | 14 +- .../{ => datainputs}/licensepicker.ts | 2 +- .../view/elements/datainputs/npmnameinput.ts | 10 +- .../view/elements/datainputs/pathinput.ts | 2 +- .../view/elements/datainputs/personinput.ts | 7 +- .../view/elements/datainputs/semverinput.ts | 10 +- .../view/elements/datainputs/urlfileinput.ts | 8 +- .../editors}/codemirroreditor.ts | 0 .../core/view/elements/editors/index.ts | 3 + .../editors}/prosemirroreditor.ts | 6 +- .../elements/{ => editors}/richtexteditor.ts | 0 .../elements/forms/attributesform.test.ts | 0 .../forms/attributesform.ts} | 6 +- .../view/elements/forms/packageform.test.ts | 0 .../{editor => elements/forms}/packageform.ts | 15 +- .../core/view/elements/forms/saveform.test.ts | 0 .../view/{ => elements}/forms/saveform.ts | 34 +- .../view/elements/forms/shareform.test.ts | 0 .../view/{ => elements}/forms/shareform.ts | 15 +- .../view/elements/forms/widgetform.test.ts | 0 .../view/elements/{ => forms}/widgetform.ts | 8 +- @webwriter/core/view/elements/index.ts | 13 - @webwriter/core/view/elements/iodialog.ts | 159 - @webwriter/core/view/elements/sortable.ts | 39 - .../elements/stylepickers/backgroundpicker.ts | 3 +- .../elements/stylepickers/borderpicker.ts | 2 +- .../{ => stylepickers}/collageimagepicker.ts | 0 .../view/elements/stylepickers/fontpicker.ts | 2 +- .../imagecoordinatepicker.ts | 0 .../core/view/elements/stylepickers/index.ts | 117 +- .../core/view/elements/ui/attachment.test.ts | 0 .../core/view/elements/{ => ui}/attachment.ts | 22 +- .../core/view/elements/ui/button.test.ts | 0 .../core/view/elements/{ => ui}/button.ts | 2 +- .../core/view/elements/ui/combobox.test.ts | 0 .../core/view/elements/{ => ui}/combobox.ts | 5 +- @webwriter/core/view/elements/ui/head.test.ts | 0 .../core/view/{layout => elements/ui}/head.ts | 4 +- .../core/view/elements/ui/layout.test.ts | 0 .../view/{layout => elements/ui}/layout.ts | 0 .../view/elements/ui/scrollbutton.test.ts | 0 .../view/elements/{ => ui}/scrollbutton.ts | 2 +- @webwriter/core/view/forms/index.ts | 21 - @webwriter/core/view/index.ts | 543 +- @webwriter/core/view/layout/commandbar.ts | 64 - @webwriter/core/view/layout/index.ts | 2 - .../index.service.ts} | 3 +- .../viewmodel/apicontroller/index.test.ts | 0 .../core/viewmodel/apicontroller/index.ts | 0 .../viewmodel/commandcontroller/index.test.ts | 0 .../index.ts} | 158 +- .../environmentcontroller/index.test.ts | 0 .../index.ts} | 10 +- .../viewmodel/iconcontroller/index.test.ts | 0 .../index.ts} | 0 @webwriter/core/viewmodel/index.test.ts | 0 @webwriter/core/viewmodel/index.ts | 62 +- .../localizationcontroller/index.test.ts | 0 .../index.ts} | 6 +- .../localization/bg.xlf | 0 .../localization/cs.xlf | 0 .../localization/da.xlf | 0 .../localization/de.xlf | 0 .../localization/el.xlf | 0 .../localization/es.xlf | 0 .../localization/et.xlf | 0 .../localization/fi.xlf | 0 .../localization/fr.xlf | 0 .../localization/generated/bg.ts | 70 +- .../localization/generated/cs.ts | 70 +- .../localization/generated/da.ts | 70 +- .../localization/generated/de.ts | 68 +- .../localization/generated/el.ts | 71 +- .../localization/generated/es.ts | 70 +- .../localization/generated/et.ts | 71 +- .../localization/generated/fi.ts | 71 +- .../localization/generated/fr.ts | 66 +- .../localization/generated/hu.ts | 71 +- .../localization/generated/id.ts | 70 +- .../localization/generated/it.ts | 70 +- .../localization/generated/ja.ts | 67 +- .../localization/generated/ko.ts | 67 +- .../localization/generated/locales.ts | 0 .../localization/generated/lt.ts | 70 +- .../localization/generated/lv.ts | 71 +- .../localization/generated/nb.ts | 70 +- .../localization/generated/nl.ts | 70 +- .../localization/generated/pl.ts | 70 +- .../localization/generated/pt-BR.ts | 66 +- .../localization/generated/pt-PT.ts | 66 +- .../localization/generated/ro.ts | 70 +- .../localization/generated/ru.ts | 70 +- .../localization/generated/sk.ts | 70 +- .../localization/generated/sl.ts | 70 +- .../localization/generated/sv.ts | 69 +- .../localization/generated/tr.ts | 70 +- .../localization/generated/uk.ts | 70 +- .../localization/generated/zh-hans.ts | 68 +- .../localization/hu.xlf | 0 .../localization/id.xlf | 0 .../localization/it.xlf | 0 .../localization/ja.xlf | 0 .../localization/ko.xlf | 0 .../localization/locales.ts} | 4 +- .../localization/lt.xlf | 0 .../localization/lv.xlf | 0 .../localization/nb.xlf | 0 .../localization/nl.xlf | 0 .../localization/pl.xlf | 0 .../localization/pt-BR.xlf | 0 .../localization/pt-PT.xlf | 0 .../localization/ro.xlf | 0 .../localization/ru.xlf | 0 .../localization/sk.xlf | 0 .../localization/sl.xlf | 0 .../localization/sv.xlf | 0 .../localization/tr.xlf | 0 .../localization/uk.xlf | 0 .../localization/zh-hans.xlf | 0 .../notificationcontroller/index.test.ts | 0 .../index.ts} | 2 +- .../settingscontroller/index.test.ts | 0 .../index.ts} | 67 +- .../viewmodel/storecontroller/index.test.ts | 0 .../index.ts} | 2 +- @webwriter/core/vite.config.js | 8 +- @webwriter/core/wdio.conf.ts | 303 + @webwriter/phet-simulation/LICENSE | 7 - .../phet-simulation/getsimulationdata.mjs | 43 - @webwriter/phet-simulation/package.json | 666 - @webwriter/phet-simulation/simulations.json | 13851 ---------------- .../phet-simulation/simulationstosnippets.mjs | 25 - .../snippets/acid-base-solutions.html | 1 - .../snippets/area-builder.html | 1 - .../snippets/area-model-algebra.html | 1 - .../snippets/area-model-decimals.html | 1 - .../snippets/area-model-introduction.html | 1 - .../snippets/area-model-multiplication.html | 1 - .../phet-simulation/snippets/arithmetic.html | 1 - .../snippets/atomic-interactions.html | 1 - .../snippets/balancing-act.html | 1 - .../balancing-chemical-equations.html | 1 - .../balloons-and-static-electricity.html | 1 - .../snippets/beers-law-lab.html | 1 - .../snippets/bending-light.html | 1 - .../snippets/blackbody-spectrum.html | 1 - .../snippets/build-a-fraction.html | 1 - .../snippets/build-a-molecule.html | 1 - .../snippets/build-a-nucleus.html | 1 - .../snippets/build-an-atom.html | 1 - .../snippets/calculus-grapher.html | 1 - .../snippets/capacitor-lab-basics.html | 1 - .../snippets/center-and-variability.html | 1 - .../snippets/charges-and-fields.html | 1 - ...rcuit-construction-kit-ac-virtual-lab.html | 1 - .../snippets/circuit-construction-kit-ac.html | 1 - ...rcuit-construction-kit-dc-virtual-lab.html | 1 - .../snippets/circuit-construction-kit-dc.html | 1 - .../snippets/collision-lab.html | 1 - .../snippets/color-vision.html | 1 - .../snippets/concentration.html | 1 - .../snippets/coulombs-law.html | 1 - .../snippets/curve-fitting.html | 1 - .../phet-simulation/snippets/density.html | 1 - .../phet-simulation/snippets/diffusion.html | 1 - .../snippets/energy-forms-and-changes.html | 1 - .../snippets/energy-skate-park-basics.html | 1 - .../snippets/energy-skate-park.html | 1 - .../snippets/equality-explorer-basics.html | 1 - .../equality-explorer-two-variables.html | 1 - .../snippets/equality-explorer.html | 1 - .../snippets/expression-exchange.html | 1 - .../snippets/faradays-law.html | 1 - .../snippets/forces-and-motion-basics.html | 1 - .../snippets/fourier-making-waves.html | 1 - .../snippets/fraction-matcher.html | 1 - .../snippets/fractions-equality.html | 1 - .../snippets/fractions-intro.html | 1 - .../snippets/fractions-mixed-numbers.html | 1 - .../phet-simulation/snippets/friction.html | 1 - .../snippets/function-builder-basics.html | 1 - .../snippets/function-builder.html | 1 - .../snippets/gas-properties.html | 1 - .../phet-simulation/snippets/gases-intro.html | 1 - .../snippets/gene-expression-essentials.html | 1 - .../snippets/geometric-optics-basics.html | 1 - .../snippets/geometric-optics.html | 1 - .../snippets/graphing-lines.html | 1 - .../snippets/graphing-quadratics.html | 1 - .../snippets/graphing-slope-intercept.html | 1 - .../snippets/gravity-and-orbits.html | 1 - .../snippets/gravity-force-lab-basics.html | 1 - .../snippets/gravity-force-lab.html | 1 - .../snippets/greenhouse-effect.html | 1 - .../phet-simulation/snippets/hookes-law.html | 1 - .../snippets/isotopes-and-atomic-mass.html | 1 - .../snippets/john-travoltage.html | 1 - .../snippets/keplers-laws.html | 1 - .../snippets/least-squares-regression.html | 1 - .../phet-simulation/snippets/make-a-ten.html | 1 - .../snippets/masses-and-springs-basics.html | 1 - .../snippets/masses-and-springs.html | 1 - .../snippets/mean-share-and-balance.html | 1 - .../phet-simulation/snippets/molarity.html | 1 - .../snippets/molecule-polarity.html | 1 - .../snippets/molecule-shapes-basics.html | 1 - .../snippets/molecule-shapes.html | 1 - .../snippets/molecules-and-light.html | 1 - .../snippets/my-solar-system.html | 1 - .../snippets/natural-selection.html | 1 - .../phet-simulation/snippets/neuron.html | 1 - .../snippets/normal-modes.html | 1 - .../snippets/number-compare.html | 1 - .../snippets/number-line-distance.html | 1 - .../snippets/number-line-integers.html | 1 - .../snippets/number-line-operations.html | 1 - .../phet-simulation/snippets/number-play.html | 1 - .../phet-simulation/snippets/ohms-law.html | 1 - .../snippets/pendulum-lab.html | 1 - .../snippets/ph-scale-basics.html | 1 - .../phet-simulation/snippets/ph-scale.html | 1 - .../snippets/plinko-probability.html | 1 - .../snippets/projectile-motion.html | 1 - .../snippets/proportion-playground.html | 1 - .../snippets/quadrilateral.html | 1 - .../snippets/ratio-and-proportion.html | 1 - .../reactants-products-and-leftovers.html | 1 - .../snippets/resistance-in-a-wire.html | 1 - .../snippets/rutherford-scattering.html | 1 - .../phet-simulation/snippets/sound-waves.html | 1 - .../snippets/states-of-matter-basics.html | 1 - .../snippets/states-of-matter.html | 1 - .../phet-simulation/snippets/trig-tour.html | 1 - .../snippets/under-pressure.html | 1 - .../phet-simulation/snippets/unit-rates.html | 1 - .../snippets/vector-addition-equations.html | 1 - .../snippets/vector-addition.html | 1 - .../snippets/wave-interference.html | 1 - .../snippets/wave-on-a-string.html | 1 - .../phet-simulation/snippets/waves-intro.html | 1 - @webwriter/quiz/.npmignore | 1 - @webwriter/quiz/LICENSE | 7 - @webwriter/quiz/custom.d.ts | 176 - @webwriter/quiz/lit-localize.json | 15 - @webwriter/quiz/localization/bg.xlf | 54 - @webwriter/quiz/localization/cs.xlf | 54 - @webwriter/quiz/localization/da.xlf | 54 - @webwriter/quiz/localization/de.xlf | 54 - @webwriter/quiz/localization/el.xlf | 54 - @webwriter/quiz/localization/es.xlf | 54 - @webwriter/quiz/localization/et.xlf | 54 - @webwriter/quiz/localization/fi.xlf | 54 - @webwriter/quiz/localization/fr.xlf | 54 - @webwriter/quiz/localization/generated/bg.ts | 25 - @webwriter/quiz/localization/generated/cs.ts | 25 - @webwriter/quiz/localization/generated/da.ts | 25 - @webwriter/quiz/localization/generated/de.ts | 25 - @webwriter/quiz/localization/generated/el.ts | 25 - @webwriter/quiz/localization/generated/es.ts | 25 - @webwriter/quiz/localization/generated/et.ts | 25 - @webwriter/quiz/localization/generated/fi.ts | 25 - @webwriter/quiz/localization/generated/fr.ts | 25 - @webwriter/quiz/localization/generated/hu.ts | 25 - @webwriter/quiz/localization/generated/id.ts | 25 - .../quiz/localization/generated/index.js | 3 - @webwriter/quiz/localization/generated/it.ts | 25 - @webwriter/quiz/localization/generated/ja.ts | 25 - @webwriter/quiz/localization/generated/ko.ts | 25 - @webwriter/quiz/localization/generated/lt.ts | 25 - @webwriter/quiz/localization/generated/lv.ts | 25 - @webwriter/quiz/localization/generated/nb.ts | 25 - @webwriter/quiz/localization/generated/nl.ts | 25 - @webwriter/quiz/localization/generated/pl.ts | 25 - .../quiz/localization/generated/pt-BR.ts | 25 - .../quiz/localization/generated/pt-PT.ts | 25 - @webwriter/quiz/localization/generated/ro.ts | 25 - @webwriter/quiz/localization/generated/ru.ts | 25 - @webwriter/quiz/localization/generated/sk.ts | 25 - @webwriter/quiz/localization/generated/sl.ts | 25 - @webwriter/quiz/localization/generated/sv.ts | 25 - @webwriter/quiz/localization/generated/tr.ts | 25 - @webwriter/quiz/localization/generated/uk.ts | 25 - .../quiz/localization/generated/zh-hans.ts | 25 - @webwriter/quiz/localization/hu.xlf | 54 - @webwriter/quiz/localization/id.xlf | 54 - @webwriter/quiz/localization/it.xlf | 54 - @webwriter/quiz/localization/ja.xlf | 54 - @webwriter/quiz/localization/ko.xlf | 54 - @webwriter/quiz/localization/lt.xlf | 54 - @webwriter/quiz/localization/lv.xlf | 54 - @webwriter/quiz/localization/nb.xlf | 54 - @webwriter/quiz/localization/nl.xlf | 54 - @webwriter/quiz/localization/pl.xlf | 54 - @webwriter/quiz/localization/pt-BR.xlf | 54 - @webwriter/quiz/localization/pt-PT.xlf | 54 - @webwriter/quiz/localization/ro.xlf | 54 - @webwriter/quiz/localization/ru.xlf | 54 - @webwriter/quiz/localization/sk.xlf | 54 - @webwriter/quiz/localization/sl.xlf | 54 - @webwriter/quiz/localization/sv.xlf | 54 - @webwriter/quiz/localization/tr.xlf | 54 - @webwriter/quiz/localization/uk.xlf | 54 - @webwriter/quiz/localization/zh-hans.xlf | 54 - @webwriter/quiz/package.json | 204 - @webwriter/quiz/src/lib/combobox.ts | 456 - @webwriter/quiz/src/lib/highlighter-fill.svg | 6 - @webwriter/quiz/src/snippets/choice.html | 8 - @webwriter/quiz/src/snippets/cloze.html | 4 - @webwriter/quiz/src/snippets/mark.html | 4 - @webwriter/quiz/src/snippets/order.html | 8 - @webwriter/quiz/src/snippets/pairing.html | 10 - @webwriter/quiz/src/snippets/speech.html | 4 - @webwriter/quiz/src/snippets/text.html | 4 - @webwriter/quiz/src/snippets/wordsearch.html | 4 - .../quiz/src/widgets/webwriter-choice-item.ts | 251 - .../quiz/src/widgets/webwriter-choice.ts | 315 - .../quiz/src/widgets/webwriter-cloze-gap.ts | 216 - .../quiz/src/widgets/webwriter-cloze.ts | 136 - @webwriter/quiz/src/widgets/webwriter-mark.ts | 432 - .../quiz/src/widgets/webwriter-order-item.ts | 438 - .../quiz/src/widgets/webwriter-order.ts | 285 - .../src/widgets/webwriter-pairing-item.ts | 161 - .../quiz/src/widgets/webwriter-pairing.ts | 193 - @webwriter/quiz/src/widgets/webwriter-quiz.ts | 282 - .../quiz/src/widgets/webwriter-speech.ts | 273 - .../src/widgets/webwriter-task-explainer.ts | 43 - .../quiz/src/widgets/webwriter-task-hint.ts | 23 - .../quiz/src/widgets/webwriter-task-prompt.ts | 24 - @webwriter/quiz/src/widgets/webwriter-task.ts | 547 - @webwriter/quiz/src/widgets/webwriter-text.ts | 136 - @webwriter/quiz/tsconfig.json | 7 - @webwriter/slides/.npmignore | 1 - @webwriter/slides/LICENSE | 7 - @webwriter/slides/custom.d.ts | 4 - @webwriter/slides/package.json | 46 - .../slides/src/snippets/webwriter-slides.html | 8 - .../slides/src/widgets/webwriter-slide.ts | 30 - .../slides/src/widgets/webwriter-slides.ts | 183 - @webwriter/slides/tsconfig.json | 6 - .../spell-check/fetchers/anthropic-fetcher.ts | 34 - .../fetchers/correction-fetcher.ts | 93 - .../spell-check/fetchers/google-fetcher.ts | 30 - .../spell-check/fetchers/llama-fetcher.ts | 4 - .../spell-check/fetchers/openai-fetcher.ts | 61 - .../fetchers/translation-fetcher.ts | 51 - @webwriter/spell-check/htmlparser.ts | 56 - @webwriter/spell-check/text-tokenizer.ts | 254 - @webwriter/textarea/.npmignore | 1 - @webwriter/textarea/build.js | 75 - @webwriter/textarea/package.json | 32 - .../src/widgets/webwriter-textarea.ts | 47 - @webwriter/textarea/tsconfig.json | 6 - @webwriter/website/package.json | 2 - @webwriter/website/src/assets/Thumbs.db | Bin 0 -> 18944 bytes @webwriter/wui/elements/collageimagepicker.ts | 255 - @webwriter/wui/elements/combobox.ts | 197 - @webwriter/wui/elements/fileinput.ts | 315 - .../wui/elements/imagecoordinatepicker.ts | 103 - @webwriter/wui/elements/index.ts | 6 - @webwriter/wui/elements/richtexteditor.ts | 167 - @webwriter/wui/elements/widgetform.ts | 775 - @webwriter/wui/index.ts | 1 - @webwriter/wui/package.json | 14 - @webwriter/wui/tsconfig.json | 19 - package.json | 60 +- scripts/autolocalize.js | 2 +- scripts/createbinaries.js | 47 - ...atejsonschema.ts => generatejsonschema.js} | 4 +- scripts/preparestatic.js | 2 +- test/specs/core/test-marshal.ts | 1 - test/tsconfig.json | 11 - test/wdio.conf.ts | 37 - 521 files changed, 5672 insertions(+), 36905 deletions(-) delete mode 100644 .github/workflows/build_tauri.yml delete mode 100644 @webwriter/app-desktop/package.json delete mode 100644 @webwriter/app-desktop/src-tauri/Cargo.lock delete mode 100644 @webwriter/app-desktop/src-tauri/Cargo.toml delete mode 100644 @webwriter/app-desktop/src-tauri/Info.plist delete mode 100644 @webwriter/app-desktop/src-tauri/build.rs delete mode 100644 @webwriter/app-desktop/src-tauri/entitlements.plist delete mode 100644 @webwriter/app-desktop/src-tauri/src/main.rs delete mode 100644 @webwriter/app-desktop/src-tauri/tauri.conf.json rename test/specs/core/test-connect.ts => @webwriter/core/model/clients/file.test.ts (100%) create mode 100644 @webwriter/core/model/clients/file.ts rename test/specs/core/test-integration.ts => @webwriter/core/model/clients/llm.test.ts (100%) create mode 100644 @webwriter/core/model/clients/llm.ts rename test/specs/core/test-state.ts => @webwriter/core/model/clients/pocketbase.test.ts (100%) create mode 100644 @webwriter/core/model/clients/pocketbase.ts delete mode 100644 @webwriter/core/model/environment/index.ts delete mode 100644 @webwriter/core/model/environment/tauri.ts rename test/specs/core/test-view.ts => @webwriter/core/model/marshal/h5p.test.ts (100%) create mode 100644 @webwriter/core/model/marshal/html.test.ts create mode 100644 @webwriter/core/model/marshal/ipynb.test.ts create mode 100644 @webwriter/core/model/marshal/markdown.test.ts create mode 100644 @webwriter/core/model/marshal/parserserializer.test.ts create mode 100644 @webwriter/core/model/marshal/zip.test.ts create mode 100644 @webwriter/core/model/schemas/account.test.ts rename @webwriter/core/model/schemas/{accounts.ts => account.ts} (73%) rename @webwriter/core/model/schemas/{contentexpression/index.grammar => contentexpression.grammar} (100%) create mode 100644 @webwriter/core/model/schemas/contentexpression.test.ts rename @webwriter/core/model/schemas/{contentexpression/index.ts => contentexpression.ts} (98%) rename @webwriter/core/model/schemas/{valuedefinition/cssproperty2.grammar => cssvalue.grammar} (99%) create mode 100644 @webwriter/core/model/schemas/cssvalue.test.ts create mode 100644 @webwriter/core/model/schemas/cssvalue.ts rename @webwriter/core/model/schemas/{resourceschema/cssspec.ts => cssvaluedefinition.data.ts} (88%) rename @webwriter/core/model/schemas/{valuedefinition/index.grammar => cssvaluedefinition.grammar} (68%) create mode 100644 @webwriter/core/model/schemas/cssvaluedefinition.ts create mode 100644 @webwriter/core/model/schemas/customelementsmanifest.test.ts rename @webwriter/core/model/schemas/{packageschema => }/customelementsmanifest.ts (100%) delete mode 100644 @webwriter/core/model/schemas/datatypes.ts create mode 100644 @webwriter/core/model/schemas/license.test.ts create mode 100644 @webwriter/core/model/schemas/license.ts create mode 100644 @webwriter/core/model/schemas/locale.test.ts create mode 100644 @webwriter/core/model/schemas/locale.ts create mode 100644 @webwriter/core/model/schemas/mediatype.test.ts create mode 100644 @webwriter/core/model/schemas/mediatype.ts create mode 100644 @webwriter/core/model/schemas/package.test.ts rename @webwriter/core/model/schemas/{packageschema/index.ts => package.ts} (90%) create mode 100644 @webwriter/core/model/schemas/resource/head.test.ts rename @webwriter/core/model/schemas/{resourceschema => resource}/head.ts (100%) create mode 100644 @webwriter/core/model/schemas/resource/htmlelementspec.test.ts rename @webwriter/core/model/schemas/{resourceschema => resource}/htmlelementspec.ts (100%) create mode 100644 @webwriter/core/model/schemas/resource/index.test.ts rename @webwriter/core/model/schemas/{resourceschema => resource}/index.ts (98%) rename @webwriter/core/model/schemas/{resourceschema/editingstyles.css => resource/plugins/base.css} (98%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/base.ts (94%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/canvas.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/deprecated.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/form.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/grammar.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/heading.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/index.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/list.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/math.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/media.ts (99%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/modal.ts (98%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/phrasing.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/section.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/style.ts (97%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/svg.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/table.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/textblock.ts (98%) rename @webwriter/core/model/schemas/{resourceschema => resource}/plugins/widget.ts (99%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/base.css (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/holiday.css (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/index.ts (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/pico.css (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/sakura.css (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/simple.css (100%) rename @webwriter/core/model/schemas/{resourceschema => resource}/themes/water.css (100%) create mode 100644 @webwriter/core/model/schemas/semver.test.ts create mode 100644 @webwriter/core/model/schemas/semver.ts delete mode 100644 @webwriter/core/model/schemas/valuedefinition/cssproperty.grammar delete mode 100644 @webwriter/core/model/schemas/valuedefinition/index.ts create mode 100644 @webwriter/core/model/stores/accountstore.test.ts create mode 100644 @webwriter/core/model/stores/documentstore.test.ts create mode 100644 @webwriter/core/model/stores/packagestore.test.ts create mode 100644 @webwriter/core/model/stores/rootstore.test.ts create mode 100644 @webwriter/core/model/stores/rootstore.ts create mode 100644 @webwriter/core/model/stores/uistore.test.ts rename test/specs/core/test-utility.ts => @webwriter/core/model/utility/index.test.ts (80%) rename @webwriter/core/{utility.ts => model/utility/index.ts} (90%) rename @webwriter/core/view/{editor/debugoverlay.ts => app/debugoverlay/index.ts} (72%) create mode 100644 @webwriter/core/view/app/editor/editor.test.ts rename @webwriter/core/view/{ => app}/editor/editor.ts (96%) create mode 100644 @webwriter/core/view/app/editor/index.ts create mode 100644 @webwriter/core/view/app/editor/nodeviews.test.ts rename @webwriter/core/view/{ => app}/editor/nodeviews.ts (96%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/README.md (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/browser.ts (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/capturekeys.ts (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/clipboard.ts (99%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/decoration.ts (99%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/dom.ts (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/domchange.ts (98%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/domcoords.ts (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/domobserver.ts (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/index.ts (99%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/input.ts (99%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/selection.ts (100%) rename @webwriter/core/view/{ => app}/editor/prosemirror-view/viewdesc.ts (99%) create mode 100644 @webwriter/core/view/app/index.test.ts create mode 100644 @webwriter/core/view/app/index.ts rename @webwriter/core/view/{editor/metaeditor.ts => app/metaeditor/index.ts} (98%) rename @webwriter/core/view/{editor/palette.ts => app/palette/index.ts} (92%) rename @webwriter/core/view/{configurator => app/settings}/accountform.ts (73%) rename @webwriter/core/view/{configurator => app/settings}/accountmanager.ts (89%) rename @webwriter/core/view/{configurator => app/settings}/configurator.ts (98%) rename @webwriter/core/view/{configurator => app/settings}/index.ts (68%) rename @webwriter/core/view/{configurator => app/settings}/keymapmanager.ts (98%) rename @webwriter/core/view/{configurator => app/settings}/packageform.ts (96%) rename @webwriter/core/view/{editor/toolbox.ts => app/toolbox/index.ts} (98%) rename @webwriter/core/view/{editor => app/toolbox}/widgetoptions.ts (99%) rename @webwriter/core/{ => view/assets}/app-icon-transparent.svg (100%) rename @webwriter/core/{ => view/assets}/app-icon.png (100%) rename @webwriter/core/{ => view/assets}/app-icon.svg (100%) rename @webwriter/{ => core/view}/assets/icons/filled/bolt.svg (100%) delete mode 100644 @webwriter/core/view/configurator/packagemanager.ts delete mode 100644 @webwriter/core/view/editor/index.ts create mode 100644 @webwriter/core/view/elements/datainputs/csspropertyinput.test.ts rename @webwriter/core/view/elements/{ => datainputs}/csspropertyinput.ts (82%) rename @webwriter/core/view/elements/datainputs/{index.ts => datainput.ts} (68%) rename @webwriter/core/view/elements/{ => datainputs}/fileinput.ts (99%) rename @webwriter/core/view/elements/{ => datainputs}/licensepicker.ts (98%) rename @webwriter/core/view/{editor => elements/editors}/codemirroreditor.ts (100%) create mode 100644 @webwriter/core/view/elements/editors/index.ts rename @webwriter/core/view/{editor => elements/editors}/prosemirroreditor.ts (99%) rename @webwriter/core/view/elements/{ => editors}/richtexteditor.ts (100%) create mode 100644 @webwriter/core/view/elements/forms/attributesform.test.ts rename @webwriter/core/view/{editor/attributesdialog.ts => elements/forms/attributesform.ts} (98%) create mode 100644 @webwriter/core/view/elements/forms/packageform.test.ts rename @webwriter/core/view/{editor => elements/forms}/packageform.ts (93%) create mode 100644 @webwriter/core/view/elements/forms/saveform.test.ts rename @webwriter/core/view/{ => elements}/forms/saveform.ts (92%) create mode 100644 @webwriter/core/view/elements/forms/shareform.test.ts rename @webwriter/core/view/{ => elements}/forms/shareform.ts (86%) create mode 100644 @webwriter/core/view/elements/forms/widgetform.test.ts rename @webwriter/core/view/elements/{ => forms}/widgetform.ts (99%) delete mode 100644 @webwriter/core/view/elements/index.ts delete mode 100644 @webwriter/core/view/elements/iodialog.ts delete mode 100644 @webwriter/core/view/elements/sortable.ts rename @webwriter/core/view/elements/{ => stylepickers}/collageimagepicker.ts (100%) rename @webwriter/core/view/elements/{ => stylepickers}/imagecoordinatepicker.ts (100%) create mode 100644 @webwriter/core/view/elements/ui/attachment.test.ts rename @webwriter/core/view/elements/{ => ui}/attachment.ts (63%) create mode 100644 @webwriter/core/view/elements/ui/button.test.ts rename @webwriter/core/view/elements/{ => ui}/button.ts (99%) create mode 100644 @webwriter/core/view/elements/ui/combobox.test.ts rename @webwriter/core/view/elements/{ => ui}/combobox.ts (97%) create mode 100644 @webwriter/core/view/elements/ui/head.test.ts rename @webwriter/core/view/{layout => elements/ui}/head.ts (97%) create mode 100644 @webwriter/core/view/elements/ui/layout.test.ts rename @webwriter/core/view/{layout => elements/ui}/layout.ts (100%) create mode 100644 @webwriter/core/view/elements/ui/scrollbutton.test.ts rename @webwriter/core/view/elements/{ => ui}/scrollbutton.ts (96%) delete mode 100644 @webwriter/core/view/forms/index.ts delete mode 100644 @webwriter/core/view/layout/commandbar.ts delete mode 100644 @webwriter/core/view/layout/index.ts rename @webwriter/core/viewmodel/{services/bundleservice.ts => apicontroller/index.service.ts} (99%) create mode 100644 @webwriter/core/viewmodel/apicontroller/index.test.ts create mode 100644 @webwriter/core/viewmodel/apicontroller/index.ts create mode 100644 @webwriter/core/viewmodel/commandcontroller/index.test.ts rename @webwriter/core/viewmodel/{commandcontroller.ts => commandcontroller/index.ts} (96%) create mode 100644 @webwriter/core/viewmodel/environmentcontroller/index.test.ts rename @webwriter/core/viewmodel/{environmentcontroller.ts => environmentcontroller/index.ts} (81%) create mode 100644 @webwriter/core/viewmodel/iconcontroller/index.test.ts rename @webwriter/core/viewmodel/{iconcontroller.ts => iconcontroller/index.ts} (100%) create mode 100644 @webwriter/core/viewmodel/index.test.ts create mode 100644 @webwriter/core/viewmodel/localizationcontroller/index.test.ts rename @webwriter/core/viewmodel/{localizationcontroller.ts => localizationcontroller/index.ts} (83%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/bg.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/cs.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/da.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/de.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/el.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/es.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/et.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/fi.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/fr.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/bg.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/cs.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/da.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/de.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/el.ts (87%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/es.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/et.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/fi.ts (87%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/fr.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/hu.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/id.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/it.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/ja.ts (87%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/ko.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/locales.ts (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/lt.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/lv.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/nb.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/nl.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/pl.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/pt-BR.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/pt-PT.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/ro.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/ru.ts (87%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/sk.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/sl.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/sv.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/tr.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/uk.ts (87%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/generated/zh-hans.ts (88%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/hu.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/id.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/it.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/ja.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/ko.xlf (100%) rename @webwriter/{quiz/localization/generated/locale-codes.js => core/viewmodel/localizationcontroller/localization/locales.ts} (97%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/lt.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/lv.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/nb.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/nl.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/pl.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/pt-BR.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/pt-PT.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/ro.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/ru.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/sk.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/sl.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/sv.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/tr.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/uk.xlf (100%) rename @webwriter/core/{ => viewmodel/localizationcontroller}/localization/zh-hans.xlf (100%) create mode 100644 @webwriter/core/viewmodel/notificationcontroller/index.test.ts rename @webwriter/core/viewmodel/{notificationcontroller.ts => notificationcontroller/index.ts} (98%) create mode 100644 @webwriter/core/viewmodel/settingscontroller/index.test.ts rename @webwriter/core/viewmodel/{settingscontroller.ts => settingscontroller/index.ts} (78%) create mode 100644 @webwriter/core/viewmodel/storecontroller/index.test.ts rename @webwriter/core/viewmodel/{storecontroller.ts => storecontroller/index.ts} (95%) create mode 100644 @webwriter/core/wdio.conf.ts delete mode 100644 @webwriter/phet-simulation/LICENSE delete mode 100644 @webwriter/phet-simulation/getsimulationdata.mjs delete mode 100644 @webwriter/phet-simulation/package.json delete mode 100644 @webwriter/phet-simulation/simulations.json delete mode 100644 @webwriter/phet-simulation/simulationstosnippets.mjs delete mode 100644 @webwriter/phet-simulation/snippets/acid-base-solutions.html delete mode 100644 @webwriter/phet-simulation/snippets/area-builder.html delete mode 100644 @webwriter/phet-simulation/snippets/area-model-algebra.html delete mode 100644 @webwriter/phet-simulation/snippets/area-model-decimals.html delete mode 100644 @webwriter/phet-simulation/snippets/area-model-introduction.html delete mode 100644 @webwriter/phet-simulation/snippets/area-model-multiplication.html delete mode 100644 @webwriter/phet-simulation/snippets/arithmetic.html delete mode 100644 @webwriter/phet-simulation/snippets/atomic-interactions.html delete mode 100644 @webwriter/phet-simulation/snippets/balancing-act.html delete mode 100644 @webwriter/phet-simulation/snippets/balancing-chemical-equations.html delete mode 100644 @webwriter/phet-simulation/snippets/balloons-and-static-electricity.html delete mode 100644 @webwriter/phet-simulation/snippets/beers-law-lab.html delete mode 100644 @webwriter/phet-simulation/snippets/bending-light.html delete mode 100644 @webwriter/phet-simulation/snippets/blackbody-spectrum.html delete mode 100644 @webwriter/phet-simulation/snippets/build-a-fraction.html delete mode 100644 @webwriter/phet-simulation/snippets/build-a-molecule.html delete mode 100644 @webwriter/phet-simulation/snippets/build-a-nucleus.html delete mode 100644 @webwriter/phet-simulation/snippets/build-an-atom.html delete mode 100644 @webwriter/phet-simulation/snippets/calculus-grapher.html delete mode 100644 @webwriter/phet-simulation/snippets/capacitor-lab-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/center-and-variability.html delete mode 100644 @webwriter/phet-simulation/snippets/charges-and-fields.html delete mode 100644 @webwriter/phet-simulation/snippets/circuit-construction-kit-ac-virtual-lab.html delete mode 100644 @webwriter/phet-simulation/snippets/circuit-construction-kit-ac.html delete mode 100644 @webwriter/phet-simulation/snippets/circuit-construction-kit-dc-virtual-lab.html delete mode 100644 @webwriter/phet-simulation/snippets/circuit-construction-kit-dc.html delete mode 100644 @webwriter/phet-simulation/snippets/collision-lab.html delete mode 100644 @webwriter/phet-simulation/snippets/color-vision.html delete mode 100644 @webwriter/phet-simulation/snippets/concentration.html delete mode 100644 @webwriter/phet-simulation/snippets/coulombs-law.html delete mode 100644 @webwriter/phet-simulation/snippets/curve-fitting.html delete mode 100644 @webwriter/phet-simulation/snippets/density.html delete mode 100644 @webwriter/phet-simulation/snippets/diffusion.html delete mode 100644 @webwriter/phet-simulation/snippets/energy-forms-and-changes.html delete mode 100644 @webwriter/phet-simulation/snippets/energy-skate-park-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/energy-skate-park.html delete mode 100644 @webwriter/phet-simulation/snippets/equality-explorer-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/equality-explorer-two-variables.html delete mode 100644 @webwriter/phet-simulation/snippets/equality-explorer.html delete mode 100644 @webwriter/phet-simulation/snippets/expression-exchange.html delete mode 100644 @webwriter/phet-simulation/snippets/faradays-law.html delete mode 100644 @webwriter/phet-simulation/snippets/forces-and-motion-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/fourier-making-waves.html delete mode 100644 @webwriter/phet-simulation/snippets/fraction-matcher.html delete mode 100644 @webwriter/phet-simulation/snippets/fractions-equality.html delete mode 100644 @webwriter/phet-simulation/snippets/fractions-intro.html delete mode 100644 @webwriter/phet-simulation/snippets/fractions-mixed-numbers.html delete mode 100644 @webwriter/phet-simulation/snippets/friction.html delete mode 100644 @webwriter/phet-simulation/snippets/function-builder-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/function-builder.html delete mode 100644 @webwriter/phet-simulation/snippets/gas-properties.html delete mode 100644 @webwriter/phet-simulation/snippets/gases-intro.html delete mode 100644 @webwriter/phet-simulation/snippets/gene-expression-essentials.html delete mode 100644 @webwriter/phet-simulation/snippets/geometric-optics-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/geometric-optics.html delete mode 100644 @webwriter/phet-simulation/snippets/graphing-lines.html delete mode 100644 @webwriter/phet-simulation/snippets/graphing-quadratics.html delete mode 100644 @webwriter/phet-simulation/snippets/graphing-slope-intercept.html delete mode 100644 @webwriter/phet-simulation/snippets/gravity-and-orbits.html delete mode 100644 @webwriter/phet-simulation/snippets/gravity-force-lab-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/gravity-force-lab.html delete mode 100644 @webwriter/phet-simulation/snippets/greenhouse-effect.html delete mode 100644 @webwriter/phet-simulation/snippets/hookes-law.html delete mode 100644 @webwriter/phet-simulation/snippets/isotopes-and-atomic-mass.html delete mode 100644 @webwriter/phet-simulation/snippets/john-travoltage.html delete mode 100644 @webwriter/phet-simulation/snippets/keplers-laws.html delete mode 100644 @webwriter/phet-simulation/snippets/least-squares-regression.html delete mode 100644 @webwriter/phet-simulation/snippets/make-a-ten.html delete mode 100644 @webwriter/phet-simulation/snippets/masses-and-springs-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/masses-and-springs.html delete mode 100644 @webwriter/phet-simulation/snippets/mean-share-and-balance.html delete mode 100644 @webwriter/phet-simulation/snippets/molarity.html delete mode 100644 @webwriter/phet-simulation/snippets/molecule-polarity.html delete mode 100644 @webwriter/phet-simulation/snippets/molecule-shapes-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/molecule-shapes.html delete mode 100644 @webwriter/phet-simulation/snippets/molecules-and-light.html delete mode 100644 @webwriter/phet-simulation/snippets/my-solar-system.html delete mode 100644 @webwriter/phet-simulation/snippets/natural-selection.html delete mode 100644 @webwriter/phet-simulation/snippets/neuron.html delete mode 100644 @webwriter/phet-simulation/snippets/normal-modes.html delete mode 100644 @webwriter/phet-simulation/snippets/number-compare.html delete mode 100644 @webwriter/phet-simulation/snippets/number-line-distance.html delete mode 100644 @webwriter/phet-simulation/snippets/number-line-integers.html delete mode 100644 @webwriter/phet-simulation/snippets/number-line-operations.html delete mode 100644 @webwriter/phet-simulation/snippets/number-play.html delete mode 100644 @webwriter/phet-simulation/snippets/ohms-law.html delete mode 100644 @webwriter/phet-simulation/snippets/pendulum-lab.html delete mode 100644 @webwriter/phet-simulation/snippets/ph-scale-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/ph-scale.html delete mode 100644 @webwriter/phet-simulation/snippets/plinko-probability.html delete mode 100644 @webwriter/phet-simulation/snippets/projectile-motion.html delete mode 100644 @webwriter/phet-simulation/snippets/proportion-playground.html delete mode 100644 @webwriter/phet-simulation/snippets/quadrilateral.html delete mode 100644 @webwriter/phet-simulation/snippets/ratio-and-proportion.html delete mode 100644 @webwriter/phet-simulation/snippets/reactants-products-and-leftovers.html delete mode 100644 @webwriter/phet-simulation/snippets/resistance-in-a-wire.html delete mode 100644 @webwriter/phet-simulation/snippets/rutherford-scattering.html delete mode 100644 @webwriter/phet-simulation/snippets/sound-waves.html delete mode 100644 @webwriter/phet-simulation/snippets/states-of-matter-basics.html delete mode 100644 @webwriter/phet-simulation/snippets/states-of-matter.html delete mode 100644 @webwriter/phet-simulation/snippets/trig-tour.html delete mode 100644 @webwriter/phet-simulation/snippets/under-pressure.html delete mode 100644 @webwriter/phet-simulation/snippets/unit-rates.html delete mode 100644 @webwriter/phet-simulation/snippets/vector-addition-equations.html delete mode 100644 @webwriter/phet-simulation/snippets/vector-addition.html delete mode 100644 @webwriter/phet-simulation/snippets/wave-interference.html delete mode 100644 @webwriter/phet-simulation/snippets/wave-on-a-string.html delete mode 100644 @webwriter/phet-simulation/snippets/waves-intro.html delete mode 100644 @webwriter/quiz/.npmignore delete mode 100644 @webwriter/quiz/LICENSE delete mode 100644 @webwriter/quiz/custom.d.ts delete mode 100644 @webwriter/quiz/lit-localize.json delete mode 100644 @webwriter/quiz/localization/bg.xlf delete mode 100644 @webwriter/quiz/localization/cs.xlf delete mode 100644 @webwriter/quiz/localization/da.xlf delete mode 100644 @webwriter/quiz/localization/de.xlf delete mode 100644 @webwriter/quiz/localization/el.xlf delete mode 100644 @webwriter/quiz/localization/es.xlf delete mode 100644 @webwriter/quiz/localization/et.xlf delete mode 100644 @webwriter/quiz/localization/fi.xlf delete mode 100644 @webwriter/quiz/localization/fr.xlf delete mode 100644 @webwriter/quiz/localization/generated/bg.ts delete mode 100644 @webwriter/quiz/localization/generated/cs.ts delete mode 100644 @webwriter/quiz/localization/generated/da.ts delete mode 100644 @webwriter/quiz/localization/generated/de.ts delete mode 100644 @webwriter/quiz/localization/generated/el.ts delete mode 100644 @webwriter/quiz/localization/generated/es.ts delete mode 100644 @webwriter/quiz/localization/generated/et.ts delete mode 100644 @webwriter/quiz/localization/generated/fi.ts delete mode 100644 @webwriter/quiz/localization/generated/fr.ts delete mode 100644 @webwriter/quiz/localization/generated/hu.ts delete mode 100644 @webwriter/quiz/localization/generated/id.ts delete mode 100644 @webwriter/quiz/localization/generated/index.js delete mode 100644 @webwriter/quiz/localization/generated/it.ts delete mode 100644 @webwriter/quiz/localization/generated/ja.ts delete mode 100644 @webwriter/quiz/localization/generated/ko.ts delete mode 100644 @webwriter/quiz/localization/generated/lt.ts delete mode 100644 @webwriter/quiz/localization/generated/lv.ts delete mode 100644 @webwriter/quiz/localization/generated/nb.ts delete mode 100644 @webwriter/quiz/localization/generated/nl.ts delete mode 100644 @webwriter/quiz/localization/generated/pl.ts delete mode 100644 @webwriter/quiz/localization/generated/pt-BR.ts delete mode 100644 @webwriter/quiz/localization/generated/pt-PT.ts delete mode 100644 @webwriter/quiz/localization/generated/ro.ts delete mode 100644 @webwriter/quiz/localization/generated/ru.ts delete mode 100644 @webwriter/quiz/localization/generated/sk.ts delete mode 100644 @webwriter/quiz/localization/generated/sl.ts delete mode 100644 @webwriter/quiz/localization/generated/sv.ts delete mode 100644 @webwriter/quiz/localization/generated/tr.ts delete mode 100644 @webwriter/quiz/localization/generated/uk.ts delete mode 100644 @webwriter/quiz/localization/generated/zh-hans.ts delete mode 100644 @webwriter/quiz/localization/hu.xlf delete mode 100644 @webwriter/quiz/localization/id.xlf delete mode 100644 @webwriter/quiz/localization/it.xlf delete mode 100644 @webwriter/quiz/localization/ja.xlf delete mode 100644 @webwriter/quiz/localization/ko.xlf delete mode 100644 @webwriter/quiz/localization/lt.xlf delete mode 100644 @webwriter/quiz/localization/lv.xlf delete mode 100644 @webwriter/quiz/localization/nb.xlf delete mode 100644 @webwriter/quiz/localization/nl.xlf delete mode 100644 @webwriter/quiz/localization/pl.xlf delete mode 100644 @webwriter/quiz/localization/pt-BR.xlf delete mode 100644 @webwriter/quiz/localization/pt-PT.xlf delete mode 100644 @webwriter/quiz/localization/ro.xlf delete mode 100644 @webwriter/quiz/localization/ru.xlf delete mode 100644 @webwriter/quiz/localization/sk.xlf delete mode 100644 @webwriter/quiz/localization/sl.xlf delete mode 100644 @webwriter/quiz/localization/sv.xlf delete mode 100644 @webwriter/quiz/localization/tr.xlf delete mode 100644 @webwriter/quiz/localization/uk.xlf delete mode 100644 @webwriter/quiz/localization/zh-hans.xlf delete mode 100644 @webwriter/quiz/package.json delete mode 100644 @webwriter/quiz/src/lib/combobox.ts delete mode 100644 @webwriter/quiz/src/lib/highlighter-fill.svg delete mode 100644 @webwriter/quiz/src/snippets/choice.html delete mode 100644 @webwriter/quiz/src/snippets/cloze.html delete mode 100644 @webwriter/quiz/src/snippets/mark.html delete mode 100644 @webwriter/quiz/src/snippets/order.html delete mode 100644 @webwriter/quiz/src/snippets/pairing.html delete mode 100644 @webwriter/quiz/src/snippets/speech.html delete mode 100644 @webwriter/quiz/src/snippets/text.html delete mode 100644 @webwriter/quiz/src/snippets/wordsearch.html delete mode 100644 @webwriter/quiz/src/widgets/webwriter-choice-item.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-choice.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-cloze-gap.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-cloze.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-mark.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-order-item.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-order.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-pairing-item.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-pairing.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-quiz.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-speech.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-task-explainer.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-task-hint.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-task-prompt.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-task.ts delete mode 100644 @webwriter/quiz/src/widgets/webwriter-text.ts delete mode 100644 @webwriter/quiz/tsconfig.json delete mode 100644 @webwriter/slides/.npmignore delete mode 100644 @webwriter/slides/LICENSE delete mode 100644 @webwriter/slides/custom.d.ts delete mode 100644 @webwriter/slides/package.json delete mode 100644 @webwriter/slides/src/snippets/webwriter-slides.html delete mode 100644 @webwriter/slides/src/widgets/webwriter-slide.ts delete mode 100644 @webwriter/slides/src/widgets/webwriter-slides.ts delete mode 100644 @webwriter/slides/tsconfig.json delete mode 100644 @webwriter/spell-check/fetchers/anthropic-fetcher.ts delete mode 100644 @webwriter/spell-check/fetchers/correction-fetcher.ts delete mode 100644 @webwriter/spell-check/fetchers/google-fetcher.ts delete mode 100644 @webwriter/spell-check/fetchers/llama-fetcher.ts delete mode 100644 @webwriter/spell-check/fetchers/openai-fetcher.ts delete mode 100644 @webwriter/spell-check/fetchers/translation-fetcher.ts delete mode 100644 @webwriter/spell-check/htmlparser.ts delete mode 100644 @webwriter/spell-check/text-tokenizer.ts delete mode 100644 @webwriter/textarea/.npmignore delete mode 100644 @webwriter/textarea/build.js delete mode 100644 @webwriter/textarea/package.json delete mode 100644 @webwriter/textarea/src/widgets/webwriter-textarea.ts delete mode 100644 @webwriter/textarea/tsconfig.json create mode 100644 @webwriter/website/src/assets/Thumbs.db delete mode 100644 @webwriter/wui/elements/collageimagepicker.ts delete mode 100644 @webwriter/wui/elements/combobox.ts delete mode 100644 @webwriter/wui/elements/fileinput.ts delete mode 100644 @webwriter/wui/elements/imagecoordinatepicker.ts delete mode 100644 @webwriter/wui/elements/index.ts delete mode 100644 @webwriter/wui/elements/richtexteditor.ts delete mode 100644 @webwriter/wui/elements/widgetform.ts delete mode 100644 @webwriter/wui/index.ts delete mode 100644 @webwriter/wui/package.json delete mode 100644 @webwriter/wui/tsconfig.json delete mode 100644 scripts/createbinaries.js rename scripts/{generatejsonschema.ts => generatejsonschema.js} (72%) delete mode 100644 test/specs/core/test-marshal.ts delete mode 100644 test/tsconfig.json delete mode 100644 test/wdio.conf.ts diff --git a/.github/workflows/build_tauri.yml b/.github/workflows/build_tauri.yml deleted file mode 100644 index 40a239d7..00000000 --- a/.github/workflows/build_tauri.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Build & Prepare Desktop Release -on: - workflow_dispatch: - -jobs: - release: - strategy: - fail-fast: false - matrix: - include: - - platform: 'macos-latest' - args: '--target aarch64-apple-darwin' - - platform: 'macos-13' - args: '--target x86_64-apple-darwin' - - platform: 'ubuntu-22.04' - args: '--verbose' - - platform: 'windows-latest' - args: '' - runs-on: ${{ matrix.platform }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Node.js setup - uses: actions/setup-node@v4 - with: - node-version: lts/* - - - name: Rust setup - uses: dtolnay/rust-toolchain@1.76 - with: - targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - - - name: Install tauri dependencies (ubuntu only) - if: matrix.platform == 'ubuntu-22.04' - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf - - - name: import windows certificate (windows only) - if: matrix.platform == 'windows-latest' - env: - WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} - WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} - run: | - New-Item -ItemType directory -Path certificate - Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE - certutil -decode certificate/tempCert.txt certificate/certificate.pfx - Remove-Item -path certificate -include tempCert.txt - Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) - - - name: Install web dependencies - run: npm install --foreground-scripts - - - name: Run prebuild actions (static resources, sidecar binaries, app icon) - run: npm run prebuild-desktop - - - name: Build web - run: npm run build-core - - - name: Build the app - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_SIGNING_IDENTITY: ${{ secrets.SIGNING_IDENTITY }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} - TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} - TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - with: - tagName: v__VERSION__ # tauri-action replaces \_\_VERSION\_\_ with the app version - releaseName: 'v__VERSION__' - releaseBody: 'See the assets to download this version and install.' - releaseDraft: true - prerelease: false - projectPath: "./@webwriter/app-desktop/src-tauri" - args: ${{ matrix.args }} diff --git a/@webwriter/app-desktop/package.json b/@webwriter/app-desktop/package.json deleted file mode 100644 index 9ab1a8ef..00000000 --- a/@webwriter/app-desktop/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "@webwriter/app-desktop", - "version": "0.12.5", - "description": "Windows/Mac/Linux version of WebWriter", - "private": true, - "author": "Frederic Salmen ", - "license": "UNLICENSED", - "devDependencies": { - "@custom-elements-manifest/analyzer": "^0.9.0", - "@tauri-apps/cli": "^1.6.0" - }, - "optionalDependencies": { - "bun": "1.1.20", - "esbuild": "^0.23.1" - } -} diff --git a/@webwriter/app-desktop/src-tauri/Cargo.lock b/@webwriter/app-desktop/src-tauri/Cargo.lock deleted file mode 100644 index fcc8478b..00000000 --- a/@webwriter/app-desktop/src-tauri/Cargo.lock +++ /dev/null @@ -1,4547 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "aho-corasick" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" - -[[package]] -name = "atk" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" -dependencies = [ - "atk-sys", - "bitflags", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.0.3", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - -[[package]] -name = "bumpalo" -version = "3.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" - -[[package]] -name = "bytemuck" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" -dependencies = [ - "serde", -] - -[[package]] -name = "cairo-rs" -version = "0.15.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" -dependencies = [ - "bitflags", - "cairo-sys-rs", - "glib", - "libc", - "thiserror", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" -dependencies = [ - "glib-sys", - "libc", - "system-deps 6.0.3", -] - -[[package]] -name = "cargo_toml" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" -dependencies = [ - "serde", - "toml 0.7.8", -] - -[[package]] -name = "cc" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" -dependencies = [ - "smallvec", -] - -[[package]] -name = "cfg-expr" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0357a6402b295ca3a86bc148e84df46c02e41f41fef186bda662557ef6328aa" -dependencies = [ - "smallvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbc37d37da9e5bce8173f3a41b71d9bf3c674deebbaceacd0ebdabde76efb03" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "winapi", -] - -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - -[[package]] -name = "cocoa" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" -dependencies = [ - "bitflags", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" -dependencies = [ - "bitflags", - "block", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "core-graphics" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" -dependencies = [ - "bitflags", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" -dependencies = [ - "bitflags", - "core-foundation", - "foreign-types", - "libc", -] - -[[package]] -name = "core-text" -version = "19.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" -dependencies = [ - "core-foundation", - "core-graphics", - "foreign-types", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.107", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" -dependencies = [ - "quote", - "syn 1.0.107", -] - -[[package]] -name = "ctor" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" -dependencies = [ - "quote", - "syn 2.0.18", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - -[[package]] -name = "cxx" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109308c20e8445959c2792e81871054c6a17e6976489a93d2769641a2ba5839c" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf4c6755cdf10798b97510e0e2b3edb9573032bd9379de8fffa59d68165494f" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.18", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882074421238e84fe3b4c65d0081de34e5b323bf64555d3e61991f76eb64a7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a076022ece33e7686fb76513518e219cca4fce5750a8ae6d1ce6c0f48fd1af9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "darling" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.18", -] - -[[package]] -name = "darling_macro" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "data-url" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn 1.0.107", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - -[[package]] -name = "dtoa-short" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" - -[[package]] -name = "embed-resource" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bde55e389bea6a966bd467ad1ad7da0ae14546a5bc794d16d1e55e7fca44881" -dependencies = [ - "cc", - "memchr", - "rustc_version 0.4.0", - "toml 0.8.8", - "vswhom", - "winreg 0.51.0", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "expat-sys" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" -dependencies = [ - "cmake", - "pkg-config", -] - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "field-offset" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" -dependencies = [ - "memoffset", - "rustc_version 0.3.3", -] - -[[package]] -name = "filetime" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys 0.42.0", -] - -[[package]] -name = "flate2" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "font-loader" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c49d6b4c11dca1a1dd931a34a9f397e2da91abe3de4110505f3530a80e560b52" -dependencies = [ - "core-foundation", - "core-text", - "libc", - "servo-fontconfig", - "winapi", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "freetype-sys" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" -dependencies = [ - "cmake", - "libc", - "pkg-config", -] - -[[package]] -name = "fsevent-sys" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" -dependencies = [ - "libc", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures-channel" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" - -[[package]] -name = "futures-executor" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" - -[[package]] -name = "futures-macro" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" - -[[package]] -name = "futures-util" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" -dependencies = [ - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" -dependencies = [ - "bitflags", - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.15.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" -dependencies = [ - "bitflags", - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.0.3", -] - -[[package]] -name = "gdk-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps 6.0.3", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps 6.0.3", -] - -[[package]] -name = "gdkx11-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps 6.0.3", - "x11", -] - -[[package]] -name = "generator" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266041a359dfa931b370ef684cceb84b166beb14f7f0421f4a6a3d0c446d12e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.39.0", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gio" -version = "0.15.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-io", - "gio-sys", - "glib", - "libc", - "once_cell", - "thiserror", -] - -[[package]] -name = "gio-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.0.3", - "winapi", -] - -[[package]] -name = "glib" -version = "0.15.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "once_cell", - "smallvec", - "thiserror", -] - -[[package]] -name = "glib-macros" -version = "0.15.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" -dependencies = [ - "anyhow", - "heck 0.4.0", - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "glib-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" -dependencies = [ - "libc", - "system-deps 6.0.3", -] - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick 0.7.20", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "gobject-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" -dependencies = [ - "glib-sys", - "libc", - "system-deps 6.0.3", -] - -[[package]] -name = "gtk" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" -dependencies = [ - "atk", - "bitflags", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "once_cell", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps 6.0.3", -] - -[[package]] -name = "gtk3-macros" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" -dependencies = [ - "anyhow", - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.2.1", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.5", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "http-range" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa 1.0.5", - "pin-project-lite", - "socket2 0.5.5", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows 0.48.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "ico" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" -dependencies = [ - "byteorder", - "png", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils", - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "image" -version = "0.24.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-rational", - "num-traits", -] - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] - -[[package]] -name = "infer" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc" -dependencies = [ - "cfb", -] - -[[package]] -name = "inotify" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" -dependencies = [ - "bitflags", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "javascriptcore-rs" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" -dependencies = [ - "bitflags", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 5.0.0", -] - -[[package]] -name = "jni" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" -dependencies = [ - "serde", - "serde_json", - "thiserror", - "treediff", -] - -[[package]] -name = "kqueue" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98" -dependencies = [ - "kqueue-sys", - "libc", -] - -[[package]] -name = "kqueue-sys" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" -dependencies = [ - "bitflags", - "libc", -] - -[[package]] -name = "kuchikiki" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 1.9.2", - "matches", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minisign-verify" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881" - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "ndk" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" -dependencies = [ - "bitflags", - "jni-sys", - "ndk-sys", - "num_enum", - "thiserror", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "notify" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d9ba6c734de18ca27c8cef5cd7058aa4ac9f63596131e4c7e41e579319032a2" -dependencies = [ - "bitflags", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "mio", - "serde", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "notify-debouncer-mini" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55ee272914f4563a2f8b8553eb6811f3c0caea81c756346bad15b7e3ef969f0" -dependencies = [ - "crossbeam-channel", - "notify", - "serde", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "open" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" -dependencies = [ - "pathdiff", - "windows-sys 0.42.0", -] - -[[package]] -name = "openssl" -version = "0.10.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_info" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4750134fb6a5d49afc80777394ad5d95b04bc12068c6abb92fae8f43817270f" -dependencies = [ - "log", - "serde", - "winapi", -] - -[[package]] -name = "os_pipe" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a252f1f8c11e84b3ab59d7a488e48e4478a93937e027076638c49536204639" -dependencies = [ - "libc", - "windows-sys 0.42.0", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pango" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" -dependencies = [ - "bitflags", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 6.0.3", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.42.0", -] - -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pest" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "plist" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225" -dependencies = [ - "base64 0.13.1", - "indexmap 1.9.2", - "line-wrap", - "serde", - "time", - "xml-rs", -] - -[[package]] -name = "png" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" -dependencies = [ - "bitflags", - "crc32fast", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-crate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" -dependencies = [ - "once_cell", - "thiserror", - "toml 0.5.10", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.107", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.8", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" -dependencies = [ - "cty", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom 0.2.8", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" -dependencies = [ - "aho-corasick 1.0.1", - "memchr", - "regex-syntax 0.7.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.28", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "reqwest" -version = "0.11.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" -dependencies = [ - "base64 0.21.2", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "winreg 0.50.0", -] - -[[package]] -name = "rfd" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea" -dependencies = [ - "block", - "dispatch", - "glib-sys", - "gobject-sys", - "gtk-sys", - "js-sys", - "lazy_static", - "log", - "objc", - "objc-foundation", - "objc_id", - "raw-window-handle", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows 0.37.0", -] - -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.16", -] - -[[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys 0.36.1", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] -name = "security-framework" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" -dependencies = [ - "serde", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.163" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.163" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "indexmap 1.9.2", - "itoa 1.0.5", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.5", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c9fdb6b00a489875b22efd4b78fe2b363b72265cc5f6eb2e2b9ee270e6140c" -dependencies = [ - "base64 0.21.2", - "chrono", - "hex", - "indexmap 1.9.2", - "indexmap 2.2.1", - "serde", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff351eb4b33600a2e138dfa0b10b65a238ea8ff8fb2387c422c5022a3e8298" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "servo-fontconfig" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" -dependencies = [ - "libc", - "servo-fontconfig-sys", -] - -[[package]] -name = "servo-fontconfig-sys" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" -dependencies = [ - "expat-sys", - "freetype-sys", - "pkg-config", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared_child" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "soup2" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" -dependencies = [ - "bitflags", - "gio", - "glib", - "libc", - "once_cell", - "soup2-sys", -] - -[[package]] -name = "soup2-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" -dependencies = [ - "bitflags", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps 5.0.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "state" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" -dependencies = [ - "loom", -] - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sys-locale" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee" -dependencies = [ - "js-sys", - "libc", - "wasm-bindgen", - "web-sys", - "windows-sys 0.45.0", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "system-deps" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" -dependencies = [ - "cfg-expr 0.9.1", - "heck 0.3.3", - "pkg-config", - "toml 0.5.10", - "version-compare 0.0.11", -] - -[[package]] -name = "system-deps" -version = "6.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff" -dependencies = [ - "cfg-expr 0.11.0", - "heck 0.4.0", - "pkg-config", - "toml 0.5.10", - "version-compare 0.1.1", -] - -[[package]] -name = "tao" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6d198e01085564cea63e976ad1566c1ba2c2e4cc79578e35d9f05521505e31" -dependencies = [ - "bitflags", - "cairo-rs", - "cc", - "cocoa", - "core-foundation", - "core-graphics", - "crossbeam-channel", - "dispatch", - "gdk", - "gdk-pixbuf", - "gdk-sys", - "gdkwayland-sys", - "gdkx11-sys", - "gio", - "glib", - "glib-sys", - "gtk", - "image", - "instant", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc", - "once_cell", - "parking_lot", - "png", - "raw-window-handle", - "scopeguard", - "serde", - "tao-macros", - "unicode-segmentation", - "uuid", - "windows 0.39.0", - "windows-implement", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b27a4bcc5eb524658234589bdffc7e7bfb996dbae6ce9393bfd39cb4159b445" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tauri" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336bc661a3f3250853fa83c6e5245449ed1c26dce5dcb28bdee7efedf6278806" -dependencies = [ - "anyhow", - "base64 0.21.2", - "bytes", - "cocoa", - "data-url", - "dirs-next", - "dunce", - "embed_plist", - "encoding_rs", - "flate2", - "futures-util", - "getrandom 0.2.8", - "glib", - "glob", - "gtk", - "heck 0.5.0", - "http", - "ignore", - "indexmap 1.9.2", - "minisign-verify", - "objc", - "once_cell", - "open", - "os_info", - "os_pipe", - "percent-encoding", - "rand 0.8.5", - "raw-window-handle", - "regex", - "reqwest", - "rfd", - "semver 1.0.16", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "shared_child", - "state", - "sys-locale", - "tar", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "tempfile", - "thiserror", - "time", - "tokio", - "url", - "uuid", - "webkit2gtk", - "webview2-com", - "windows 0.39.0", - "zip", -] - -[[package]] -name = "tauri-build" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c6ec7a5c3296330c7818478948b422967ce4649094696c985f61d50076d29c" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs-next", - "heck 0.5.0", - "json-patch", - "semver 1.0.16", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "1.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1aed706708ff1200ec12de9cfbf2582b5d8ec05f6a7293911091effbd22036b" -dependencies = [ - "base64 0.21.2", - "brotli", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote", - "regex", - "semver 1.0.16", - "serde", - "serde_json", - "sha2", - "tauri-utils", - "thiserror", - "time", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "1.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88f831d2973ae4f81a706a0004e67dac87f2e4439973bbe98efbd73825d8ede" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 1.0.107", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin-fs-extra" -version = "0.0.0" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#07406f1c9d7817c95dc9ebf4bfe2cdb1ea352045" -dependencies = [ - "log", - "serde", - "serde_json", - "tauri", - "thiserror", -] - -[[package]] -name = "tauri-plugin-fs-watch" -version = "0.0.0" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#07406f1c9d7817c95dc9ebf4bfe2cdb1ea352045" -dependencies = [ - "log", - "notify", - "notify-debouncer-mini", - "serde", - "serde_json", - "tauri", - "thiserror", -] - -[[package]] -name = "tauri-runtime" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3068ed62b63dedc705558f4248c7ecbd5561f0f8050949859ea0db2326f26012" -dependencies = [ - "gtk", - "http", - "http-range", - "rand 0.8.5", - "raw-window-handle", - "serde", - "serde_json", - "tauri-utils", - "thiserror", - "url", - "uuid", - "webview2-com", - "windows 0.39.0", -] - -[[package]] -name = "tauri-runtime-wry" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c3db170233096aa30330feadcd895bf9317be97e624458560a20e814db7955" -dependencies = [ - "cocoa", - "gtk", - "percent-encoding", - "rand 0.8.5", - "raw-window-handle", - "tauri-runtime", - "tauri-utils", - "uuid", - "webkit2gtk", - "webview2-com", - "windows 0.39.0", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826db448309d382dac14d520f0c0a40839b87b57b977e59cf5f296b3ace6a93" -dependencies = [ - "brotli", - "ctor", - "dunce", - "glob", - "heck 0.5.0", - "html5ever", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.2", - "proc-macro2", - "quote", - "semver 1.0.16", - "serde", - "serde_json", - "serde_with", - "thiserror", - "url", - "walkdir", - "windows-version", -] - -[[package]] -name = "tauri-winres" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" -dependencies = [ - "embed-resource", - "toml 0.7.8", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" -dependencies = [ - "itoa 1.0.5", - "libc", - "num_threads", - "serde", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "pin-project-lite", - "socket2 0.4.10", - "windows-sys 0.42.0", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - -[[package]] -name = "toml" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.21.0", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.2.1", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap 2.2.1", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "treediff" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" -dependencies = [ - "serde_json", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "uuid" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" -dependencies = [ - "getrandom 0.2.8", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" - -[[package]] -name = "version-compare" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.107", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "wasm-streams" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" -dependencies = [ - "bitflags", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup2", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" -dependencies = [ - "atk-sys", - "bitflags", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pango-sys", - "pkg-config", - "soup2-sys", - "system-deps 6.0.3", -] - -[[package]] -name = "webview2-com" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.39.0", - "windows-implement", -] - -[[package]] -name = "webview2-com-macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "webview2-com-sys" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" -dependencies = [ - "regex", - "serde", - "serde_json", - "thiserror", - "windows 0.39.0", - "windows-bindgen", - "windows-metadata", -] - -[[package]] -name = "webwriter" -version = "0.12.5" -dependencies = [ - "font-loader", - "serde", - "serde_json", - "tauri", - "tauri-build", - "tauri-plugin-fs-extra", - "tauri-plugin-fs-watch", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" -dependencies = [ - "windows_aarch64_msvc 0.37.0", - "windows_i686_gnu 0.37.0", - "windows_i686_msvc 0.37.0", - "windows_x86_64_gnu 0.37.0", - "windows_x86_64_msvc 0.37.0", -] - -[[package]] -name = "windows" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" -dependencies = [ - "windows-implement", - "windows_aarch64_msvc 0.39.0", - "windows_i686_gnu 0.39.0", - "windows_i686_msvc 0.39.0", - "windows_x86_64_gnu 0.39.0", - "windows_x86_64_msvc 0.39.0", -] - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-bindgen" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" -dependencies = [ - "windows-metadata", - "windows-tokens", -] - -[[package]] -name = "windows-implement" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" -dependencies = [ - "syn 1.0.107", - "windows-tokens", -] - -[[package]] -name = "windows-metadata" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows-tokens" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" - -[[package]] -name = "windows-version" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" - -[[package]] -name = "windows_i686_gnu" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" - -[[package]] -name = "windows_i686_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winreg" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "937f3df7948156640f46aacef17a70db0de5917bda9c92b0f751f3a955b588fc" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wry" -version = "0.24.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00711278ed357350d44c749c286786ecac644e044e4da410d466212152383b45" -dependencies = [ - "base64 0.13.1", - "block", - "cocoa", - "core-graphics", - "crossbeam-channel", - "dunce", - "gdk", - "gio", - "glib", - "gtk", - "html5ever", - "http", - "kuchikiki", - "libc", - "log", - "objc", - "objc_id", - "once_cell", - "serde", - "serde_json", - "sha2", - "soup2", - "tao", - "thiserror", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.39.0", - "windows-implement", -] - -[[package]] -name = "x11" -version = "2.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2638d5b9c17ac40575fb54bb461a4b1d2a8d1b4ffcc4ff237d254ec59ddeb82" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1536d6965a5d4e573c7ef73a2c15ebcd0b2de3347bdf526c34c297c00ac40f0" -dependencies = [ - "lazy_static", - "libc", - "pkg-config", -] - -[[package]] -name = "xattr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" -dependencies = [ - "libc", -] - -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" - -[[package]] -name = "zip" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" -dependencies = [ - "byteorder", - "crc32fast", - "crossbeam-utils", -] diff --git a/@webwriter/app-desktop/src-tauri/Cargo.toml b/@webwriter/app-desktop/src-tauri/Cargo.toml deleted file mode 100644 index d5d8b670..00000000 --- a/@webwriter/app-desktop/src-tauri/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "webwriter" -version = "0.12.5" -description = "Windows/Mac/Linux version of WebWriter" -authors = ["Frederic Salmen "] -license = "UNLICENSED" -repository = "https://github.com/salmenf/webwriter.git" -default-run = "webwriter" -edition = "2021" -rust-version = "1.76" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[build-dependencies] -tauri-build = { version = "1.5.3", features = [] } - -[dependencies] -serde_json = "1" -serde = { version = "1", features = ["derive"] } -tauri = { version = "1.7.1", features = [ "macos-private-api", "devtools", "dialog-all", "fs-all", "http-all", "os-all", "path-all", "process-all", "shell-execute", "shell-open", "shell-sidecar", "updater", "window-all", "window-data-url"] } -tauri-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } -tauri-plugin-fs-watch = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } -font-loader = "0.11.0" - -[features] -# by default Tauri runs in production mode -# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL -default = [ "custom-protocol" ] -# this feature is used for production builds where `devPath` points to the filesystem -# DO NOT remove this -custom-protocol = [ "tauri/custom-protocol" ] diff --git a/@webwriter/app-desktop/src-tauri/Info.plist b/@webwriter/app-desktop/src-tauri/Info.plist deleted file mode 100644 index 90c04326..00000000 --- a/@webwriter/app-desktop/src-tauri/Info.plist +++ /dev/null @@ -1,12 +0,0 @@ - - - - - UIApplicationSupportsPrintCommand - - NSMicrophoneUsageDescription - Record audio to insert into explorables - NSCameraUsageDescription - Record video to insert into explorables - - diff --git a/@webwriter/app-desktop/src-tauri/build.rs b/@webwriter/app-desktop/src-tauri/build.rs deleted file mode 100644 index 795b9b7c..00000000 --- a/@webwriter/app-desktop/src-tauri/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build() -} diff --git a/@webwriter/app-desktop/src-tauri/entitlements.plist b/@webwriter/app-desktop/src-tauri/entitlements.plist deleted file mode 100644 index 51b50873..00000000 --- a/@webwriter/app-desktop/src-tauri/entitlements.plist +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.device.camera - - com.apple.security.device.audio-input - - - diff --git a/@webwriter/app-desktop/src-tauri/src/main.rs b/@webwriter/app-desktop/src-tauri/src/main.rs deleted file mode 100644 index 1fea4b88..00000000 --- a/@webwriter/app-desktop/src-tauri/src/main.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![cfg_attr( - all(not(debug_assertions), target_os = "windows"), - windows_subsystem = "windows" -)] - -use font_loader::system_fonts; - -fn main() { - tauri::Builder::default() - .plugin(tauri_plugin_fs_extra::init()) -// .plugin(tauri_plugin_persisted_scope::init()) - .plugin(tauri_plugin_fs_watch::init()) - .invoke_handler(tauri::generate_handler![get_system_fonts]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} - -#[tauri::command] -fn get_system_fonts() -> Vec { - return system_fonts::query_all(); -} \ No newline at end of file diff --git a/@webwriter/app-desktop/src-tauri/tauri.conf.json b/@webwriter/app-desktop/src-tauri/tauri.conf.json deleted file mode 100644 index 9dc5085e..00000000 --- a/@webwriter/app-desktop/src-tauri/tauri.conf.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "$schema": "../../../node_modules/@tauri-apps/cli/schema.json", - "build": { - "beforeBuildCommand": "", - "beforeDevCommand": "", - "devPath": "http://localhost:5173", - "distDir": "../../core/dist" - }, - "package": { - "productName": "WebWriter", - "version": "../package.json" - }, - "tauri": { - "allowlist": { - "all": false, - - "fs": { - "all": true, - "scope": { - "allow": ["**", "**/*", "*/**"], - "requireLiteralLeadingDot": false - } - }, - "os": { - "all": true - }, - "path": { - "all": true - }, - "dialog": { - "all": true - }, - "http": { - "all": true, - "scope": ["https://**"] - }, - "shell": { - "sidecar": true, - "execute": true, - "open": ".*", - "scope": [ - {"name": "bin/bun", "args": true, "sidecar": true}, - {"name": "bin/esbuild", "args": true, "sidecar": true} - ] - }, - "window": { - "all": true - }, - "process": { - "all": true - } - }, - "bundle": { - "active": true, - "category": "Education", - "copyright": "(c) 2024 All rights reserved", - "deb": { - "depends": [] - }, - "appimage": { - "bundleMediaFramework": true - }, - "externalBin": [ - "bin/bun", - "bin/esbuild" - ], - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "identifier": "webwriter.webwriter", - "longDescription": "", - "macOS": { - "entitlements": "./entitlements.plist" - }, - "resources": [], - "shortDescription": "", - "targets": "all" - }, - "security": { - "csp": null - }, - "macOSPrivateApi": true, - "windows": [ - { - "fileDropEnabled": false, - "fullscreen": false, - "height": 600, - "resizable": true, - "title": "WebWriter", - "width": 800, - "minWidth": 600, - "minHeight": 600 - } - ], - "updater": { - "active": true, - "dialog": true, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM1NTZENzEwN0EwMjVBRUUKUldUdVdnSjZFTmRXTlF1STVaVGtZcUo1M2EzcmNJMzRjQnhtVmlvcWVsb3h5WE8wRkJ3NXR1YVQK", - "endpoints": [ - "https://github.com/webwriter-app/webwriter/releases/latest/download/latest.json" - ] - } - } -} diff --git a/@webwriter/core/index.html b/@webwriter/core/index.html index fed9388f..0c291230 100644 --- a/@webwriter/core/index.html +++ b/@webwriter/core/index.html @@ -77,7 +77,7 @@
- + diff --git a/@webwriter/core/lit-localize.json b/@webwriter/core/lit-localize.json index 3681bd98..f9b70b29 100644 --- a/@webwriter/core/lit-localize.json +++ b/@webwriter/core/lit-localize.json @@ -5,12 +5,12 @@ "tsConfig": "./tsconfig.json", "output": { "mode": "runtime", - "outputDir": "./localization/generated", - "localeCodesModule": "./@webwriter/core/localization/generated/locales.ts" + "outputDir": "./viewmodel/localizationcontroller/localization/generated", + "localeCodesModule": "./@webwriter/core/viewmodel/localizationcontroller/localization/locales.ts" }, "interchange": { "format": "xliff", - "xliffDir": "./localization" + "xliffDir": "./viewmodel/localizationcontroller/localization" } } \ No newline at end of file diff --git a/test/specs/core/test-connect.ts b/@webwriter/core/model/clients/file.test.ts similarity index 100% rename from test/specs/core/test-connect.ts rename to @webwriter/core/model/clients/file.test.ts diff --git a/@webwriter/core/model/clients/file.ts b/@webwriter/core/model/clients/file.ts new file mode 100644 index 00000000..7ca44bc7 --- /dev/null +++ b/@webwriter/core/model/clients/file.ts @@ -0,0 +1,208 @@ +import { marshal, FileAccount } from "#model" + +function writeFileDownload(uri: string, name?: string) { + const a = document.createElement("a"); + name && a.setAttribute("download", name); + a.style.display = "none"; + a.href = uri; + document.body.appendChild(a); + a.click(); + a.remove(); + } + + async function readFileInput() { + return new Promise( + async (resolve, reject) => { + let file: File; + try { + file = await pickFileInput(); + } catch (err) { + return reject(new Error("User cancelled")); + } + const reader = new FileReader(); + reader.readAsText(file); + reader.addEventListener("load", () => + typeof reader.result === "string" + ? resolve(reader.result!) + : resolve(new Uint8Array(reader.result!)) + ); + } + ); + } + + async function pickFileInput() { + const input = document.createElement("input"); + input.type = "file"; + return new Promise((resolve, reject) => { + input.addEventListener("change", () => { + if (input.files && input.files.length && input.files.item(0)) { + const file = input.files.item(0)!; + resolve(file); + } + }); + input.addEventListener("cancel", reject); + input.click(); + }); + } + + const SAVE_FILTERS = [ + ...Object.entries(marshal) + .filter(([k, v]) => !v.isParseOnly) + .map(([k, v]) => ({ + name: "Explorable", + extensions: v.extensions as unknown as string[], + types: { [k]: v.extensions.map((ext) => "." + ext) }, + })), + ]; + const LOAD_FILTERS = [ + { + name: "Explorable", + extensions: Object.values(marshal).flatMap((v) => v.extensions), + types: Object.fromEntries( + Object.keys(marshal).map((k) => [ + k, + (marshal as any)[k].extensions.map((ext: string) => "." + ext), + ]) + ), + }, + ...Object.entries(marshal).map(([k, v]) => ({ + name: "Explorable", + extensions: v.extensions as unknown as string[], + types: { [k]: v.extensions.map((ext) => "." + ext) }, + })), + ]; + + type FileFormat = keyof typeof marshal; + + +// @ts-ignore: Fix account types +export class FileClient implements DocumentClient { + constructor( + readonly account: FileAccount + ) {} + + get fileSystemSupported() { + return "createWritable" in FileSystemFileHandle.prototype; + } + + get showOpenFilePickerSupported() { + return "showOpenFilePicker" in window; + } + + get showSaveFilePickerSupported() { + return "showSaveFilePicker" in window; + } + + async saveDocument( + doc: string | Uint8Array, + url?: string | URL | FileSystemFileHandle, + title?: string + ) { + if (this.fileSystemSupported && this.showSaveFilePickerSupported) { + const handle = + (url as FileSystemFileHandle) ?? + ((await this.pickSave()) as FileSystemFileHandle | undefined); + const writable = await handle.createWritable(); + await writable.write(doc); + await writable.close(); + return handle; + } else { + const blob = new Blob([doc]); + const url = URL.createObjectURL(blob); + writeFileDownload(url, "explorable.html"); + URL.revokeObjectURL(url); + } + } + + async loadDocument( + url?: string | FileSystemFileHandle | URL + ) { + if (this.showOpenFilePickerSupported) { + const handle = + (url as FileSystemFileHandle) ?? + ((await this.pickLoad()) as FileSystemFileHandle | undefined); + if (!handle) { + return; + } + const file = await handle.getFile(); + const reader = new FileReader(); + reader.readAsText(file); + return new Promise((resolve) => { + reader.addEventListener("load", () => + typeof reader.result === "string" + ? resolve(reader.result!) + : resolve(new Uint8Array(reader.result!)) + ); + }); + } else if (url) { + throw Error( + "Not supported in your browser or permissions for File System Access API are missing (try Chrome or Edge)" + ); + } else { + return readFileInput(); + } + } + + async pickSave( + filters: typeof SAVE_FILTERS = SAVE_FILTERS, + defaultPath?: string + ) { + if (this.showSaveFilePickerSupported) { + try { + let handle: FileSystemFileHandle = await ( + window as any + ).showSaveFilePicker({ + startIn: "documents", + types: filters.map((filter) => ({ + description: filter.name, + accept: filter.types, + })), + }); + handle = Array.isArray(handle) ? handle[0] : handle; + return handle; + } catch (err) { + if ((err as Error)?.name === "AbortError") { + return undefined; + } else { + throw err; + } + } + } else { + throw Error( + "Not supported in your browser or permissions for File System Access API are missing (try Chrome or Edge)" + ); + } + } + + async pickLoad(filters: typeof LOAD_FILTERS = LOAD_FILTERS) { + if ("showOpenFilePicker" in window) { + try { + let handle: FileSystemFileHandle = await ( + window as any + ).showOpenFilePicker({ + startIn: "documents", + types: filters.map((filter) => ({ + description: filter.name, + accept: filter.types, + })), + }); + handle = Array.isArray(handle) ? handle[0] : handle; + return handle; + } catch (err) { + if ((err as Error)?.name === "AbortError") { + return undefined; + } else { + throw err; + } + } + } else { + throw Error( + "Not supported in your browser or permissions for File System Access API are missing (try Chrome or Edge)" + ); + } + } + + isClientURL(url: URL) { + return url.protocol === "file:"; + } + } \ No newline at end of file diff --git a/@webwriter/core/model/clients/index.ts b/@webwriter/core/model/clients/index.ts index 274c73ec..5761d842 100644 --- a/@webwriter/core/model/clients/index.ts +++ b/@webwriter/core/model/clients/index.ts @@ -1,109 +1,12 @@ -import { DialogFilter } from "@tauri-apps/api/dialog"; -import { getFileExtension } from "../../utility"; -import { Environment } from "../environment"; -import { - Account, - FileAccount, - LLMAccount, - NpmAccount, - PocketbaseAccount, -} from "../schemas/accounts"; -import PocketBase, { - AsyncAuthStore, - AuthModel, - BaseAuthStore, - BaseModel, - CollectionModel, - RecordModel, - SerializeOptions, -} from "pocketbase"; -import { - EditorStateWithHead, - Package, - Resource, - defaultConfig, -} from "../schemas"; -import marshal from "../marshal"; -import { Schema } from "prosemirror-model"; -import { toJS } from "mobx"; +import { Account, LLMAccount, Package } from "#schemas"; +import { FileClient, LLMClient, PocketbaseClient } from "#model"; -function writeFileDownload(uri: string, name?: string) { - const a = document.createElement("a"); - name && a.setAttribute("download", name); - a.style.display = "none"; - a.href = uri; - document.body.appendChild(a); - a.click(); - a.remove(); -} - -async function readFileInput() { - return new Promise( - async (resolve, reject) => { - let file: File; - try { - file = await pickFileInput(); - } catch (err) { - return reject(new Error("User cancelled")); - } - const reader = new FileReader(); - reader.readAsText(file); - reader.addEventListener("load", () => - typeof reader.result === "string" - ? resolve(reader.result!) - : resolve(new Uint8Array(reader.result!)) - ); - } - ); -} - -async function pickFileInput() { - const input = document.createElement("input"); - input.type = "file"; - return new Promise((resolve, reject) => { - input.addEventListener("change", () => { - if (input.files && input.files.length && input.files.item(0)) { - const file = input.files.item(0)!; - resolve(file); - } - }); - input.addEventListener("cancel", reject); - input.click(); - }); -} - -const SAVE_FILTERS = [ - ...Object.entries(marshal) - .filter(([k, v]) => !v.isParseOnly) - .map(([k, v]) => ({ - name: "Explorable", - extensions: v.extensions as unknown as string[], - types: { [k]: v.extensions.map((ext) => "." + ext) }, - })), -]; -const LOAD_FILTERS = [ - { - name: "Explorable", - extensions: Object.values(marshal).flatMap((v) => v.extensions), - types: Object.fromEntries( - Object.keys(marshal).map((k) => [ - k, - (marshal as any)[k].extensions.map((ext: string) => "." + ext), - ]) - ), - }, - ...Object.entries(marshal).map(([k, v]) => ({ - name: "Explorable", - extensions: v.extensions as unknown as string[], - types: { [k]: v.extensions.map((ext) => "." + ext) }, - })), -]; - -type FileFormat = keyof typeof marshal; +export * from "./file"; +export * from "./llm"; +export * from "./pocketbase"; export interface Client { readonly account: Account; - readonly Environment: Environment; } export interface DocumentClient extends Client { @@ -114,11 +17,11 @@ export interface DocumentClient extends Client { doc: string | Uint8Array, url?: URL | string, filename?: string - ): Promise; + ): Promise; /** Load a document from the given `url` in the configured storage. If no `url` is provided, let the configured storage handle the specific location.*/ - loadDocument(url?: URL | string): Promise; + loadDocument(url?: FileSystemFileHandle | URL | string): Promise; /** Delete a document at the given URL. */ - deleteDocument?(url: string | URL): Promise; + deleteDocument?(url: FileSystemFileHandle | URL): Promise; /** Search the documents of configured storage. If no `options` are provided, return all documents. */ searchDocuments?(options: { page?: number; @@ -130,11 +33,11 @@ export interface DocumentClient extends Client { skipTotal?: boolean; }): Promise; /** Pick a location for saving in the configured storage. Returns the location as a URL. */ - pickSave?(): Promise; + pickSave?(): Promise; /** Pick a document from the configured storage. Returns the location as a URL. */ - pickLoad?(): Promise; + pickLoad?(): Promise; /** Get the public URL of the given document. */ - getSharingURLForDocument?(url: string | URL): Promise; + getSharingURLForDocument?(url: FileSystemFileHandle | URL): Promise; } export interface PackageClient extends Client { @@ -178,450 +81,8 @@ export interface AuthenticationClient extends Client { get isSignedIn(): boolean; } -// @ts-ignore: Fix account types -export class FileClient implements DocumentClient { - constructor( - readonly account: FileAccount, - readonly Environment?: Environment - ) {} - - get fileSystemSupported() { - return "createWritable" in FileSystemFileHandle.prototype; - } - - get showOpenFilePickerSupported() { - return "showOpenFilePicker" in window; - } - - get showSaveFilePickerSupported() { - return "showSaveFilePicker" in window; - } - - async saveDocument( - doc: string | Uint8Array, - url?: string | URL | FileSystemFileHandle, - title?: string - ) { - if ( - WEBWRITER_ENVIRONMENT.backend === "tauri" && - this.Environment && - (!url || !(url instanceof FileSystemFileHandle)) - ) { - const { OS, FS } = this.Environment; - const binary = doc instanceof Uint8Array; - const urlObj = url - ? new URL(url) - : ((await this.pickSave(undefined, title)) as URL | undefined); - if (!urlObj) { - return; - } - let path = decodeURI(urlObj.pathname).slice(1); - path = ["darwin", "linux"].includes(await OS.platform()) - ? "/" + path - : path; - await FS.writeFile(path, doc, binary ? "binary" : "utf8"); - return urlObj; - } else { - if (this.fileSystemSupported && this.showSaveFilePickerSupported) { - const handle = - (url as FileSystemFileHandle) ?? - ((await this.pickSave()) as FileSystemFileHandle | undefined); - const writable = await handle.createWritable(); - await writable.write(doc); - await writable.close(); - return handle; - } else { - const blob = new Blob([doc]); - const url = URL.createObjectURL(blob); - writeFileDownload(url, "explorable.html"); - URL.revokeObjectURL(url); - } - } - } - - async loadDocument( - url?: string | FileSystemFileHandle | URL, - binary = false - ) { - if ( - WEBWRITER_ENVIRONMENT.backend === "tauri" && - this.Environment && - !(url instanceof FileSystemFileHandle) - ) { - const { OS, FS } = this.Environment; - const urlObj = url - ? new URL(url) - : ((await this.pickLoad()) as URL | undefined); - if (!urlObj) { - return; - } - let path = decodeURI(urlObj.pathname).slice(1); - path = ["darwin", "linux"].includes(await OS.platform()) - ? "/" + path - : path; - let data = await FS.readFile(path, binary ? "binary" : "utf8"); - return data; - } else if (this.showOpenFilePickerSupported) { - const handle = - (url as FileSystemFileHandle) ?? - ((await this.pickLoad()) as FileSystemFileHandle | undefined); - if (!handle) { - return; - } - const file = await handle.getFile(); - const reader = new FileReader(); - reader.readAsText(file); - return new Promise((resolve) => { - reader.addEventListener("load", () => - typeof reader.result === "string" - ? resolve(reader.result!) - : resolve(new Uint8Array(reader.result!)) - ); - }); - } else if (url) { - throw Error( - "Not supported in your browser or permissions for File System Access API are missing (try Chrome or Edge)" - ); - } else { - return readFileInput(); - } - } - - async pickSave( - filters: typeof SAVE_FILTERS = SAVE_FILTERS, - defaultPath?: string - ) { - if (WEBWRITER_ENVIRONMENT.backend === "tauri" && this.Environment) { - const path = - ((await this.Environment.Dialog.promptWrite({ - filters, - defaultPath, - })) as null | string) ?? undefined; - return path ? new URL(path, "file://") : undefined; - } else if (this.showSaveFilePickerSupported) { - try { - let handle: FileSystemFileHandle = await ( - window as any - ).showSaveFilePicker({ - startIn: "documents", - types: filters.map((filter) => ({ - description: filter.name, - accept: filter.types, - })), - }); - handle = Array.isArray(handle) ? handle[0] : handle; - return handle; - } catch (err) { - if ((err as Error)?.name === "AbortError") { - return undefined; - } else { - throw err; - } - } - } else { - throw Error( - "Not supported in your browser or permissions for File System Access API are missing (try Chrome or Edge)" - ); - } - } - - async pickLoad(filters: typeof LOAD_FILTERS = LOAD_FILTERS) { - if (WEBWRITER_ENVIRONMENT.backend === "tauri" && this.Environment) { - const path = - ((await this.Environment.Dialog.promptRead({ filters })) as - | null - | string) ?? undefined; - return path ? new URL(path, "file://") : undefined; - } else { - if ("showOpenFilePicker" in window) { - try { - let handle: FileSystemFileHandle = await ( - window as any - ).showOpenFilePicker({ - startIn: "documents", - types: filters.map((filter) => ({ - description: filter.name, - accept: filter.types, - })), - }); - handle = Array.isArray(handle) ? handle[0] : handle; - return handle; - } catch (err) { - if ((err as Error)?.name === "AbortError") { - return undefined; - } else { - throw err; - } - } - } else { - throw Error( - "Not supported in your browser or permissions for File System Access API are missing (try Chrome or Edge)" - ); - } - } - } - - isClientURL(url: URL) { - return url.protocol === "file:"; - } -} - -export class NpmClient implements PackageClient, AuthenticationClient { - constructor( - readonly account: NpmAccount, - readonly Environment: Environment - ) {} - - get isSignedIn(): boolean { - // TODO: Check if token is present - return false; - } - - async signIn() { - // TODO: Configure the package manager to use this registry - } - - async signOut() { - // TODO: If using this registry, clear it - } - - async searchPackages( - text: string, - params?: { - size?: number; - quality?: number; - popularity?: number; - maintenance?: number; - } - ) { - const { objects } = await this.Environment.search(text, params); - return objects.map(({ package: pkg }) => new Package(pkg)); - } - - // Not supported by Bun yet - /* - async publishPackage(path: string) { - - } - - async unpublishPackage(path: string) { - - }*/ -} - -class PocketbaseAuthStore extends BaseAuthStore { - constructor( - readonly account: PocketbaseAccount, - readonly onChangeAccount?: (account: PocketbaseAccount) => Promise - ) { - super(); - } - - get token(): string { - return this.account.token ?? ""; - } - - get model(): AuthModel | null { - return this.account.model ?? null; - } - - save(token: string, model?: AuthModel): void { - if (token) { - const newAccount = new PocketbaseAccount({ - ...this.account, - token, - model: model as any, - }); - this.onChangeAccount && this.onChangeAccount(newAccount); - } - } - - clear(): void { - const newAccount = new PocketbaseAccount({ - ...this.account, - token: undefined, - model: undefined, - }); - this.onChangeAccount && this.onChangeAccount(newAccount); - } -} - -export class LLMClient implements LLMApiClient { - constructor( - readonly account: LLMAccount, - readonly Environment: Environment - ) {} - - getModel() { - return this.account.model; - } - - getCompany() { - return this.account.company; - } - - getApiKey() { - return this.account.apiKey; - } -} -export class PocketbaseClient implements DocumentClient, AuthenticationClient { - #pocketbase: PocketBase; - - constructor( - readonly account: PocketbaseAccount, - readonly Environment: Environment, - onChangeAccount?: (account: PocketbaseAccount) => Promise - ) { - this.#pocketbase = new PocketBase( - account.url, - new PocketbaseAuthStore(account, onChangeAccount) - ); - } - - async signIn(options?: { - password?: string; - cookie?: string; - updateAccount?: boolean; - }) { - if (this.isSignedIn) { - return; - } - if (options?.password) { - const authModel = await this.#pocketbase - .collection("users") - .authWithPassword(this.account.email, options.password); - if (options.updateAccount) { - this.account.token = authModel.token; - } - } else if (options?.cookie) { - return this.#pocketbase.authStore.loadFromCookie(options.cookie); - } - } - - async signOut(updateAccount = false) { - this.#pocketbase.authStore.clear(); - if (updateAccount) { - this.account.token = undefined; - } - } - - get isSignedIn() { - const authStore = this.#pocketbase.authStore; - return (authStore.isAuthRecord || authStore.isAdmin) && authStore.isValid; - } - - private recordModelToURL(model: RecordModel) { - const url = new URL( - this.#pocketbase.buildUrl( - `/api/collections/${model.collectionName}/records/${model.id}` - ) - ); - url.username = this.account.email; - url.searchParams.set("created", model.created); - url.searchParams.set("updated", model.updated); - url.searchParams.set("filename", model.file); - url.searchParams.set("mediatype", "text/html"); - url.searchParams.set("apitype", "pocketbase"); - return url; - } - - private idFromURL(url: string | URL) { - return new URL(url).pathname.split("/").at(-1); - } - - private filenameFromURL(url: string | URL) { - return new URL(url).searchParams.get("filename") ?? undefined; - } - - isClientURL(url: URL) { - const originMatches = new URL(this.account.url).origin === url.origin; - const usernameMatches = - (this.account.id ?? this.account.email) === decodeURIComponent(url.username); - return originMatches && usernameMatches; - } - - async searchDocuments(options: { - page?: number; - perPage?: number; - sort?: string; - filter?: string; - expand?: string; - fields?: string; - skipTotal?: boolean; - }) { - await this.signIn({ cookie: this.account.token }); - const docs = this.#pocketbase.collection("documents"); - const results = await docs.getList(options.page, options.perPage, options); - return results.items.map((item) => this.recordModelToURL(item)); - } - - async saveDocument( - doc: string | Uint8Array, - url?: string | URL, - filename?: string - ) { - const resolvedFilename = - filename || - (url - ? new URL(url).searchParams - .get("filename") - ?.replace(/\_\w{10}\.(\w+)/, ".$1") || "" - : ""); - await this.signIn({ cookie: this.account.token }); - const docs = this.#pocketbase.collection("documents"); - const formData = new FormData(); - formData.append("owner", this.#pocketbase.authStore.model!.id); - if (url) { - const urlObj = new URL(url); - const id = urlObj.pathname.split("/").at(-1)!; - const toUpdate = await this.#pocketbase - .collection("documents") - .getOne(id); - const toUpdateFilename = toUpdate.file.replace(/\_\w{10}\.(\w+)/, ".$1"); - const file = new File([doc], toUpdateFilename); - formData.append("file", file); - const updated = await this.#pocketbase - .collection("documents") - .update(id, formData); - return this.recordModelToURL(updated); - } else { - const file = new File([doc], resolvedFilename); - formData.append("file", file); - const model = await docs.create(formData); - return this.recordModelToURL(model); - } - } - - async loadDocument(url?: string | URL) { - await this.signIn({ cookie: this.account.token }); - if (!url) { - return undefined; - } - const id = this.idFromURL(url)!; - const filename = this.filenameFromURL(url)!; - const record = await this.#pocketbase.collection("documents").getOne(id); - const fileURL = this.#pocketbase.files.getUrl(record, filename); - const response = await fetch(fileURL); - const blob = await response.blob(); - const content = await blob.text(); - return content; - } - - async deleteDocument(url: string | URL) { - await this.signIn({ cookie: this.account.token }); - const id = this.idFromURL(url); - return this.#pocketbase.collection("documents").delete(id!); - } - - async getSharingURLForDocument(url: string | URL) { - const id = this.idFromURL(url)!; - return new URL(`/explorables/${id}`, this.#pocketbase.baseUrl); - } -} - export default { file: FileClient, pocketbase: PocketbaseClient, - npm: NpmClient, llm: LLMClient, }; diff --git a/test/specs/core/test-integration.ts b/@webwriter/core/model/clients/llm.test.ts similarity index 100% rename from test/specs/core/test-integration.ts rename to @webwriter/core/model/clients/llm.test.ts diff --git a/@webwriter/core/model/clients/llm.ts b/@webwriter/core/model/clients/llm.ts new file mode 100644 index 00000000..ee0c2018 --- /dev/null +++ b/@webwriter/core/model/clients/llm.ts @@ -0,0 +1,526 @@ +import { LLMAccount, LLMApiClient } from "#model" +import Anthropic from "@anthropic-ai/sdk"; + +export class LLMClient implements LLMApiClient { + constructor( + readonly account: LLMAccount + ) {} + + getModel() { + return this.account.model; + } + + getCompany() { + return this.account.company; + } + + getApiKey() { + return this.account.apiKey; + } +} + +function validateClaudeApiKey(apiKey: string): boolean { + return apiKey.length > 0; +} + +const anthropic = new Anthropic({ + apiKey: "placeholder", + dangerouslyAllowBrowser: true, +}); + +const fetchAnthropicChatCompletion = async ( + systemPrompt: string, + messages: any[], + apiKey: string, + model: string +) => { + if (!validateClaudeApiKey(apiKey)) { + throw new Error("API key is not valid."); + } + + anthropic.apiKey = apiKey; + + const msg = await anthropic.messages.create({ + model: model, + max_tokens: 1000, + temperature: 0, + system: systemPrompt, + messages: messages, + }); + + return msg; +}; +export { validateClaudeApiKey, fetchAnthropicChatCompletion }; + +{ + /* + ### Prompt design ### + + I want the model to: + * correct snippets of text for spelling and grammar mistakes + * just return the corrected text + * keep as much as possible original + * if the original text is unintelligible, just return the original text + * keep in mind that it's an excerpt from a text, so no need to correct akwardly cut words at the start or end of the snippet + */ +} + +const instructionMessageEN = ` + You are a highly skilled proofreader and editor. Your task is to correct spelling and grammar mistakes in the following text snippet. Follow these guidelines: + + 1. Correct any spelling errors or grammatical mistakes you find. + 2. Maintain as much of the original text as possible. Only make changes where necessary for correctness. + 3. If the text is completely unintelligible, return it unchanged. + 4. Remember that this is an excerpt from a larger text. Do not attempt to correct or complete words that may be cut off at the beginning or end of the snippet. + 5. Do not add any explanations or comments. Simply return the corrected text. + 6. If no corrections are needed, return the original text unchanged. + + Here's the text to check and correct: +`; + +const instructionMessageDE = ` + Sie sind ein hochqualifizierter Korrekturleser und Redakteur. Ihre Aufgabe ist es, Rechtschreib- und Grammatikfehler in dem folgenden Textausschnitt zu korrigieren. Befolgen Sie diese Richtlinien: + + 1. Korrigieren Sie alle Rechtschreib- und Grammatikfehler, die Sie finden. + 2. Behalten Sie den Originaltext so weit wie möglich bei. Nehmen Sie nur dort Änderungen vor, wo es für die Korrektheit notwendig ist. + 3. Wenn der Text völlig unverständlich ist, senden Sie ihn unverändert zurück. + 4. Denken Sie daran, dass es sich um einen Auszug aus einem größeren Text handelt. Versuchen Sie nicht, Wörter zu korrigieren oder zu vervollständigen, die am Anfang oder Ende des Auszugs abgeschnitten sind. + 5. Fügen Sie keine Erklärungen oder Kommentare hinzu. Geben Sie einfach den korrigierten Text zurück. + 6. Wenn keine Korrekturen erforderlich sind, senden Sie den Originaltext unverändert zurück. + + Hier ist der zu prüfende und zu korrigierende Text: +`; + +const fetchInstructionMessage = (language: string): string => { + console.log("language", language); + switch (language) { + case "en": + return instructionMessageEN; + case "de": + return instructionMessageDE; + default: + return instructionMessageEN; + } +}; + +/** + * Fetch text correction from different AI providers. + */ +export function fetchGrammarCorrection( + text: string, + apiKey: string, + company: string, + model: string, + language: string +): any | void { + const instructionMessage = fetchInstructionMessage(language); + + switch (company) { + case "OpenAI": + return fetchOpenAIChatCompletion( + instructionMessage, + [{ role: "user", content: text }], + apiKey, + model + ); + + case "Google": + return fetchGeminiChatCompletion(instructionMessage, text, apiKey, model); + + case "Anthropic": + return fetchAnthropicChatCompletion( + instructionMessage, + [{ role: "user", content: text }], + apiKey, + model + ); + + default: + throw new Error("Company not supported"); + } +} + +import { GoogleGenerativeAI } from "@google/generative-ai"; + +function validateGeminiApiKey(apiKey: string): boolean { + return apiKey.length > 0; +} +const genAI = new GoogleGenerativeAI("placeholder"); + +async function fetchGeminiChatCompletion( + systemPrompt: string, + text: string, + apiKey: string, + model: string +) { + if (!validateGeminiApiKey(apiKey)) { + throw new Error("API key is not valid."); + } + + genAI.apiKey = apiKey; + // const genAImodel = genAI.getGenerativeModel({ model: "gemini-1.5-flash" }); + const genAImodel = genAI.getGenerativeModel({ + model: model, + systemInstruction: systemPrompt, + }); + + const result = await genAImodel.generateContent(text); + const response = await result.response; + return response.text(); +} + +function validateLlamaApiKey(apiKey: string): boolean { + return apiKey.length === 32; +} + +import { OpenAI } from "openai"; +import { APIPromise } from "openai/core"; +import { ChatCompletionMessageParam, ChatCompletion } from "openai/resources/chat/completions"; + +// Initialize the OpenAI API client with a placeholder API key. +const openai = new OpenAI({ + apiKey: "placeholder", // Use a placeholder for the API key until it's securely fetched. + dangerouslyAllowBrowser: true, +}); + +/** + * Helper function to create a system message for the ChatCompletion API. + + */ +function createSystemMessage(systemPrompt: string): ChatCompletionMessageParam { + return { + role: "system", + content: [ + { + type: "text", + text: systemPrompt, + }, + ], + }; +} + +/** + * Fetch a chat completion response from OpenAI. + */ +function fetchOpenAIChatCompletion( + systemPrompt: string, + messages: ChatCompletionMessageParam[], + apiKey: string, + model: string +): APIPromise { + if (!apiKey) { + throw new Error("OPENAI_API_KEY environment variable is not defined."); + } + + openai.apiKey = apiKey; + + const messageFinal: ChatCompletionMessageParam[] = [ + createSystemMessage(systemPrompt), + ...messages, + ]; + + console.log("fetchChatCompletion", messageFinal); + + return openai.chat.completions.create({ + model, + temperature: 0, // Ensure deterministic output with no randomness. + messages: messageFinal, + max_tokens: 1024, + top_p: 1, // Use the top 100% of probability mass for decoding. + frequency_penalty: 0, // No penalty for using repetitive words. + presence_penalty: 0, // No penalty for mentioning words frequently. + response_format: { type: "text" }, // Expect a textual response format. + }); +} + +/** + * Fetch text correction or translation from different AI providers. + */ +export function fetchTranslation( + text: string, + apiKey: string, + company: string, + model: string, + language: string +): any | void { + const instructionMessage = fetchInstructionMessage(language); + + switch (company) { + case "OpenAI": + return fetchOpenAIChatCompletion( + instructionMessage, + [{ role: "user", content: text }], + apiKey, + model + ); + + case "Google": + return fetchGeminiChatCompletion(instructionMessage, text, apiKey, model); + + case "Anthropic": + return fetchAnthropicChatCompletion( + instructionMessage, + [{ role: "user", content: text }], + apiKey, + model + ); + + default: + throw new Error("Company not supported"); + } +} + +import { + EditorState, + Plugin, + TextSelection, + Transaction, +} from "prosemirror-state"; + +type Token = { + type: "word" | "punctuation" | "space"; + value: string; + position: number; +}; + +export function tokenizeText(text: string): Token[] { + const tokens: Token[] = []; + const regex = /(\w+(?:['’-]\w+)*|[^\w\s]|\s+)/g; // regex to match words, punctuation, and spaces + let match; + + while ((match = regex.exec(text)) !== null) { + const value = match[0]; + const position = match.index; + let type: "word" | "punctuation" | "space"; + + if (/^\w+(?:[']\w+)?$/.test(value)) { + type = "word"; + } else if (/^\s+$/.test(value)) { + type = "space"; + } else { + type = "punctuation"; + } + + tokens.push({ type, value, position }); + } + + return tokens; +} + +type DiffToken = { + type: "insert" | "delete" | "unchanged"; + token: Token; +}; + +/* + * Given two arrays of tokens, return a list of diff tokens that represent the + * differences between the two arrays. + */ + +export function diffTokens( + originalTokens: Token[], + correctedTokens: Token[] +): DiffToken[] { + const m = originalTokens.length; + const n = correctedTokens.length; + const dp: number[][] = Array(m + 1) + .fill(null) + .map(() => Array(n + 1).fill(0)); + + // Fill the dp table + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + if (originalTokens[i - 1].value === correctedTokens[j - 1].value) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + // Backtrack to find the diff + const diff: DiffToken[] = []; + let i = m, + j = n; + while (i > 0 || j > 0) { + if ( + i > 0 && + j > 0 && + originalTokens[i - 1].value === correctedTokens[j - 1].value + ) { + diff.unshift({ type: "unchanged", token: originalTokens[i - 1] }); + i--; + j--; + } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) { + diff.unshift({ type: "insert", token: correctedTokens[j - 1] }); + j--; + } else { + diff.unshift({ type: "delete", token: originalTokens[i - 1] }); + i--; + } + } + console.log("uncompressed diff:", diff); + const compressedDiff = compressDiffTokens(diff); + + return compressedDiff; +} + +function compressDiffTokens(diff: DiffToken[]): DiffToken[] { + const compressedDiff: DiffToken[] = []; + let lastToken: DiffToken | null = null; + + for (const token of diff) { + if (lastToken && lastToken.type === token.type) { + lastToken.token.value += token.token.value; + } else { + compressedDiff.push(token); + lastToken = token; + } + } + + // account for correct insertion positions + compressedDiff.forEach((diff, i) => { + if (diff.type === "unchanged") { + const nextDiff = compressedDiff[i + 1]; + if (nextDiff?.type === "insert") { + nextDiff.token.position = diff.token.position + diff.token.value.length; + } + } + }); + + return compressedDiff; +} + +type Suggestion = { + type: "replace" | "insert" | "delete"; + original: Token; + corrected: Token; +}; + +/* + * Given a list of diff tokens, return a list of suggestions that can be applied + * to the original text to correct it. + */ + +export function matchDiffs(diff: DiffToken[]): Suggestion[] { + const suggestions: Suggestion[] = []; + let i = 0; + while (i < diff.length) { + const token = diff[i]; + if (token.type === "delete") { + if (i + 1 < diff.length && diff[i + 1].type === "insert") { + suggestions.push({ + type: "replace", + original: token.token, + corrected: diff[i + 1].token, + }); + i += 2; + } else { + suggestions.push({ + type: "delete", + original: token.token, + corrected: token.token, + }); + i++; + } + } else if (token.type === "insert") { + suggestions.push({ + type: "insert", + original: token.token, + corrected: token.token, + }); + i++; + } else { + i++; + } + } + return suggestions; +} + +/* + * creates a Transaction that removes all grammar Marks from the document + */ +export function removeGrammarSuggestions( + editorState: EditorState +): Transaction { + const { tr, doc, schema } = editorState; + const grammarMark = schema.marks.grammar; + + // We'll use this to track positions as we potentially delete content + let offset = 0; + + doc.descendants((node, pos) => { + if (node.isInline) { + const mark = node.marks.find((m) => m.type === grammarMark); + if (mark) { + const from = pos + offset; + const to = from + node.nodeSize; + + if (mark.attrs.isInsert) { + // For insertions, delete the content + tr.delete(from, to); + // Update offset to account for deleted content + offset -= to - from; + } else { + // For corrections, just remove the mark + tr.removeMark(from, to, grammarMark); + } + } + } + return true; + }); + + return tr; +} + +/* + * creates a Transaction that applies the given grammar suggestions to the document + */ +export function applyGrammarSuggestions( + editorState: EditorState, + suggestions: Suggestion[] +): Transaction { + let tr = editorState.tr; + + // Sort suggestions in reverse order to avoid position shifts + const sortedSuggestions = [...suggestions].sort( + (a, b) => b.original.position - a.original.position + ); + + for (const suggestion of sortedSuggestions) { + const from = suggestion.original.position + 1; + const to = from + suggestion.original.value.length; + + switch (suggestion.type) { + case "replace": + tr = tr.addMark( + from, + to, + editorState.schema.marks.grammar.create({ + corrected: suggestion.corrected.value, + }) + ); + break; + case "insert": + tr = tr.insertText(suggestion.corrected.value, from); + tr = tr.addMark( + from, + from + suggestion.corrected.value.length, + editorState.schema.marks.grammar.create({ + corrected: suggestion.corrected.value, + isInsert: true, + }) + ); + break; + case "delete": + tr = tr.addMark( + from, + to, + editorState.schema.marks.grammar.create({ corrected: "" }) + ); + break; + } + } + + return tr; +} \ No newline at end of file diff --git a/test/specs/core/test-state.ts b/@webwriter/core/model/clients/pocketbase.test.ts similarity index 100% rename from test/specs/core/test-state.ts rename to @webwriter/core/model/clients/pocketbase.test.ts diff --git a/@webwriter/core/model/clients/pocketbase.ts b/@webwriter/core/model/clients/pocketbase.ts new file mode 100644 index 00000000..a90158fe --- /dev/null +++ b/@webwriter/core/model/clients/pocketbase.ts @@ -0,0 +1,200 @@ +import PocketBase, {AuthModel, BaseAuthStore, RecordModel} from "pocketbase"; +import { PocketbaseAccount } from "#schemas"; +import { AuthenticationClient, DocumentClient } from "."; + +class PocketbaseAuthStore extends BaseAuthStore { + constructor( + readonly account: PocketbaseAccount, + readonly onChangeAccount?: (account: PocketbaseAccount) => Promise + ) { + super(); + } + + get token(): string { + return this.account.token ?? ""; + } + + get model(): AuthModel | null { + return this.account.model ?? null; + } + + save(token: string, model?: AuthModel): void { + if (token) { + const newAccount = new PocketbaseAccount({ + ...this.account, + token, + model: model as any, + }); + this.onChangeAccount && this.onChangeAccount(newAccount); + } + } + + clear(): void { + const newAccount = new PocketbaseAccount({ + ...this.account, + token: undefined, + model: undefined, + }); + this.onChangeAccount && this.onChangeAccount(newAccount); + } + } + + export class PocketbaseClient implements DocumentClient, AuthenticationClient { + #pocketbase: PocketBase; + + constructor( + readonly account: PocketbaseAccount, + onChangeAccount?: (account: PocketbaseAccount) => Promise + ) { + this.#pocketbase = new PocketBase( + account.url, + new PocketbaseAuthStore(account, onChangeAccount) + ); + } + + async signIn(options?: { + password?: string; + cookie?: string; + updateAccount?: boolean; + }) { + if (this.isSignedIn) { + return; + } + if (options?.password) { + const authModel = await this.#pocketbase + .collection("users") + .authWithPassword(this.account.email, options.password); + if (options.updateAccount) { + this.account.token = authModel.token; + } + } else if (options?.cookie) { + return this.#pocketbase.authStore.loadFromCookie(options.cookie); + } + } + + async signOut(updateAccount = false) { + this.#pocketbase.authStore.clear(); + if (updateAccount) { + this.account.token = undefined; + } + } + + get isSignedIn() { + const authStore = this.#pocketbase.authStore; + return (authStore.isAuthRecord || authStore.isAdmin) && authStore.isValid; + } + + private recordModelToURL(model: RecordModel) { + const url = new URL( + this.#pocketbase.buildUrl( + `/api/collections/${model.collectionName}/records/${model.id}` + ) + ); + url.username = this.account.email; + url.searchParams.set("created", model.created); + url.searchParams.set("updated", model.updated); + url.searchParams.set("filename", model.file); + url.searchParams.set("mediatype", "text/html"); + url.searchParams.set("apitype", "pocketbase"); + return url; + } + + private idFromURL(url: string | URL) { + return new URL(url).pathname.split("/").at(-1); + } + + private filenameFromURL(url: string | URL) { + return new URL(url).searchParams.get("filename") ?? undefined; + } + + isClientURL(url: URL) { + const originMatches = new URL(this.account.url).origin === url.origin; + const usernameMatches = + (this.account.id ?? this.account.email) === decodeURIComponent(url.username); + return originMatches && usernameMatches; + } + + async searchDocuments(options: { + page?: number; + perPage?: number; + sort?: string; + filter?: string; + expand?: string; + fields?: string; + skipTotal?: boolean; + }) { + await this.signIn({ cookie: this.account.token }); + const docs = this.#pocketbase.collection("documents"); + const results = await docs.getList(options.page, options.perPage, options); + return results.items.map((item) => this.recordModelToURL(item)); + } + + async saveDocument( + doc: string | Uint8Array, + url?: string | URL, + filename?: string + ) { + const resolvedFilename = + filename || + (url + ? new URL(url).searchParams + .get("filename") + ?.replace(/\_\w{10}\.(\w+)/, ".$1") || "" + : ""); + await this.signIn({ cookie: this.account.token }); + const docs = this.#pocketbase.collection("documents"); + const formData = new FormData(); + formData.append("owner", this.#pocketbase.authStore.model!.id); + if (url) { + const urlObj = new URL(url); + const id = urlObj.pathname.split("/").at(-1)!; + const toUpdate = await this.#pocketbase + .collection("documents") + .getOne(id); + const toUpdateFilename = toUpdate.file.replace(/\_\w{10}\.(\w+)/, ".$1"); + const file = new File([doc], toUpdateFilename); + formData.append("file", file); + const updated = await this.#pocketbase + .collection("documents") + .update(id, formData); + return this.recordModelToURL(updated); + } else { + const file = new File([doc], resolvedFilename); + formData.append("file", file); + const model = await docs.create(formData); + return this.recordModelToURL(model); + } + } + + async loadDocument(url?: string | URL) { + await this.signIn({ cookie: this.account.token }); + if (!url) { + return undefined; + } + const id = this.idFromURL(url)!; + const filename = this.filenameFromURL(url)!; + const record = await this.#pocketbase.collection("documents").getOne(id); + const fileURL = this.#pocketbase.files.getUrl(record, filename); + const response = await fetch(fileURL); + const blob = await response.blob(); + const content = await blob.text(); + return content; + } + + async deleteDocument(url: FileSystemFileHandle | URL) { + if(url instanceof FileSystemFileHandle) { + throw TypeError("Received FileSystemFileHandle, expected URL") + } + await this.signIn({ cookie: this.account.token }); + const id = this.idFromURL(url); + return this.#pocketbase.collection("documents").delete(id!); + } + + async getSharingURLForDocument(url: FileSystemFileHandle | URL) { + if(url instanceof FileSystemFileHandle) { + throw TypeError("Received FileSystemFileHandle, expected URL") + } + const id = this.idFromURL(url)!; + return new URL(`/explorables/${id}`, this.#pocketbase.baseUrl); + } + } \ No newline at end of file diff --git a/@webwriter/core/model/environment/index.ts b/@webwriter/core/model/environment/index.ts deleted file mode 100644 index 2efae5d2..00000000 --- a/@webwriter/core/model/environment/index.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { WindowOptions } from "@tauri-apps/api/window"; -import { Package } from ".."; - -export * from "./tauri"; -// export * from "./node" - -export type HTTPMethod = - | "GET" - | "HEAD" - | "POST" - | "PUT" - | "DELETE" - | "CONNECT" - | "OPTIONS" - | "TRACE" - | "PATCH"; - -export interface Stats { - type: "file" | "dir"; - mode: any; - size: number; - ino: any; - mtimeMs: any; - ctimeMs: any; - uid: 1; - gid: 1; - dev: 1; - isFile(): boolean; - isDirectory(): boolean; - isSymbolicLink(): boolean; -} - -export type Request = { - url: string; - method: HTTPMethod; - headers: Record; - body: string | Uint8Array[]; - onProgress: Function; - timeout: number; -}; - -export type Response = { - url: string; - method: HTTPMethod; - headers: Record; - body: string | Uint8Array[]; -}; - -export type SearchResults = { - total: number; - time: string; - objects: { - package: Package; - score: { - final: number; - detail: { quality: number; popularity: number; maintenance: number }; - }; - searchScore: number; - }[]; -}; - -export type Platform = - | "linux" - | "darwin" - | "ios" - | "freebsd" - | "dragonfly" - | "netbsd" - | "openbsd" - | "solaris" - | "android" - | "win32"; - -export type Arch = - | "x86" - | "x86_64" - | "arm" - | "aarch64" - | "mips" - | "mips64" - | "powerpc" - | "powerpc64" - | "riscv64" - | "s390x" - | "sparc64"; - -export type OpenDialogOptions = { - defaultPath?: string; - directory?: boolean; - filters?: { name: string; extensions: string[] }[]; - multiple?: boolean; - recursive?: boolean; - title?: string; -}; - -export type SaveDialogOptions = { - defaultPath?: string; - filters?: { name: string; extensions: string[] }[]; - title?: string; -}; - -export type WatchEvent = { kind: "any" | "AnyContinous"; path: string }; - -export type FileSystemAPI = { - mkdir: (path: string, options?: { mode: number }) => Promise; - rmdir: (path: string, options?: undefined) => Promise; - readdir: (path: string, options?: undefined) => Promise; - readFile: ( - path: string, - options?: { encoding?: "utf8" } | string | undefined - ) => Promise; - writeFile: ( - path: string, - data: Uint8Array | string, - options?: { mode: number; encoding?: "utf8" } | string | undefined - ) => Promise; - exists: (path: string) => Promise; - unlink: (path: string, options?: undefined) => Promise; - rename: (oldPath: string, newPath: string) => Promise; - stat: (path: string, options?: undefined) => Promise; - lstat: (path: string, options?: undefined) => Promise; - symlink: (targetPath: string, linkPath: string) => Promise; - readlink: (path: string, options?: undefined) => Promise; -}; - -export type PathAPI = { - join: (...parts: string[]) => Promise; - normalize: (path: string) => Promise; - basename: (path: string) => Promise; - dirname: (path: string) => Promise; - extname: (path: string) => Promise; - resolve: (...paths: string[]) => Promise; - isAbsolute: (path: string) => Promise; - appDir: () => Promise; -}; - -export type ShellAPI = { - open: (path: string, openWith?: string) => Promise; -}; - -export type HTTPAPI = { - request: ({ - url, - method, - headers, - body, - onProgress, - timeout, - }: Request) => Promise; - fetch: typeof fetch; -}; - -export type OSAPI = { - platform: () => Promise; - arch: () => Promise; -}; - -export type ConfirmDialogOptions = { - cancelLabel?: string; - okLabel?: string; - title?: string; - type?: "info" | "warning" | "error"; -}; - -export type DialogAPI = { - promptRead: ( - options?: OpenDialogOptions - ) => Promise; - promptWrite: (options?: SaveDialogOptions) => Promise; - confirm: ( - message: string, - options?: ConfirmDialogOptions - ) => Promise; -}; - -export type WindowCloseBehavior = - | "closeAllIfLastVisible" - | "hideOnCloseUnlessLast" - | "closeOthersOnReload"; - -export type Environment = { - FS: FileSystemAPI; - Path: PathAPI; - Shell: ShellAPI; - HTTP: HTTPAPI; - OS: OSAPI; - Dialog: DialogAPI; - bundle: (args?: string[], cwd?: string) => Promise; - search: ( - text: string, - params?: { - size?: number; - from?: number; - quality?: number; - popularity?: number; - maintenance?: number; - }, - searchEndpoint?: string - ) => Promise; - pm: ( - command: string, - commandArgs?: string[], - cwd?: string - ) => Promise; - watch: ( - paths: string | string[], - cb?: (event: { - attrs: any; - paths: string[]; - type: { create?: any; modify?: any; remove?: any }; - }) => void, - options?: { recursive?: boolean; delayMs?: number } - ) => Promise<() => void>; // wait for FileSystemObserver, shim with polling? - getSystemFonts: () => Promise; // wait for Local Font Access API? - createWindow: ( - url?: string, - options?: WindowOptions & { label?: string; hideOnClose?: boolean } - ) => Promise; - setWindowCloseBehavior: ( - behaviors: WindowCloseBehavior[], - closeConfirm?: () => Promise - ) => void; - getWindowLabel: () => string; - checkUpdate: () => Promise<{ date: string; version: string }>; - installUpdate: () => Promise; -}; diff --git a/@webwriter/core/model/environment/tauri.ts b/@webwriter/core/model/environment/tauri.ts deleted file mode 100644 index 30147b52..00000000 --- a/@webwriter/core/model/environment/tauri.ts +++ /dev/null @@ -1,278 +0,0 @@ -import {readTextFile, readBinaryFile, writeTextFile, writeBinaryFile, removeFile, readDir, createDir, removeDir, exists, renameFile} from "@tauri-apps/api/fs" -import {join, normalize, basename, dirname, extname, resolve, isAbsolute, appDataDir as appDir} from "@tauri-apps/api/path" -import {Command, open} from "@tauri-apps/api/shell" -import {arch, platform} from "@tauri-apps/api/os" -import {open as promptRead, save as promptWrite} from "@tauri-apps/api/dialog" -import {fetch, Body, ResponseType} from "@tauri-apps/api/http" -import {Buffer} from "buffer"; window.Buffer = Buffer -import {metadata} from "tauri-plugin-fs-extra-api" -import { invoke } from "@tauri-apps/api/tauri" -import { WebviewWindow, WindowOptions, getAll, getCurrent } from "@tauri-apps/api/window" -import {listen} from "@tauri-apps/api/event" -import {exit} from "@tauri-apps/api/process" - -import { DialogAPI, FileSystemAPI, HTTPAPI, OSAPI, PathAPI, Response, ShellAPI, Stats, WindowCloseBehavior } from "." -import { idle } from "../../utility" - -export {watchImmediate as watch} from "tauri-plugin-fs-watch-api" -import {confirm} from "@tauri-apps/api/dialog" -export { checkUpdate, installUpdate } from "@tauri-apps/api/updater" - -const HTTP_STATUS = { - '200': 'OK', - '201': 'Created', - '202': 'Accepted', - '203': 'Non-Authoritative Information', - '204': 'No Content', - '205': 'Reset Content', - '206': 'Partial Content', - '300': 'Multiple Choices', - '301': 'Moved Permanently', - '302': 'Found', - '303': 'See Other', - '304': 'Not Modified', - '305': 'Use Proxy', - '306': 'Unused', - '307': 'Temporary Redirect', - '400': 'Bad Request', - '401': 'Unauthorized', - '402': 'Payment Required', - '403': 'Forbidden', - '404': 'Not Found', - '405': 'Method Not Allowed', - '406': 'Not Acceptable', - '407': 'Proxy Authentication Required', - '408': 'Request Timeout', - '409': 'Conflict', - '410': 'Gone', - '411': 'Length Required', - '412': 'Precondition Required', - '413': 'Request Entry Too Large', - '414': 'Request-URI Too Long', - '415': 'Unsupported Media Type', - '416': 'Requested Range Not Satisfiable', - '417': 'Expectation Failed', - '418': 'I\'m a teapot', - '429': 'Too Many Requests', - '500': 'Internal Server Error', - '501': 'Not Implemented', - '502': 'Bad Gateway', - '503': 'Service Unavailable', - '504': 'Gateway Timeout', - '505': 'HTTP Version Not Supported', -}; - -export const FS: FileSystemAPI = { - async readFile(path, options="utf8") { - const encoding = typeof options === "string"? options: options.encoding - return encoding === "utf8"? readTextFile(path): readBinaryFile(path) - }, - async writeFile(path, data, options="utf8") { - const encoding = typeof options === "string"? options: options.encoding - return encoding === "utf8" - ? writeTextFile(path, data as string) - : writeBinaryFile({path, contents: data as Uint8Array}) - }, - async unlink(path) { - return removeFile(path) - }, - async exists(path: string) { - return exists(path) - }, - async readdir(path) { - return (await readDir(path)).map(entry => entry.name) as string[] - }, - async mkdir(path) { - return createDir(path, {recursive: true}) - }, - async rmdir(path) { - return removeDir(path, {recursive: true}) - }, - async stat(path) { - try { - const stats = await metadata(path) - return { - ...stats, - type: stats.isDir? "dir": "file", - atime: stats.accessedAt, - mtime: stats.modifiedAt, - ctime: stats.createdAt, - atimeMs: stats.accessedAt.getMilliseconds(), - mtimeMs: stats.modifiedAt.getMilliseconds(), - ctimeMs: stats.createdAt.getMilliseconds(), - isDirectory: () => stats.isDir, - isSymbolicLink: () => stats.isSymlink - } as unknown as Stats - } - catch(err) {} - }, - async lstat(path) { - return FS.stat(path) - }, - async readlink() { // mocked to support isomorphic-git - console.error("readlink") - return "READLINK NOT IMPLEMENTED" - }, - async symlink() { // mocked to support isomorphic-git - console.error("symlink") - }, - async rename(oldPath, newPath) { - return renameFile(oldPath, newPath) - }, - -} - -export const Path: PathAPI = { - join, normalize, basename, dirname, extname, isAbsolute, resolve, appDir -} - -export const Shell: ShellAPI = {open} - -export const OS: OSAPI = {arch, platform} - -export const Dialog: DialogAPI = {promptRead, promptWrite, confirm} - -export const HTTP: HTTPAPI = { - async request({url, method, headers, body, onProgress, timeout}) { - const response = await fetch(url, {method, headers, body: body? Body.bytes(body[0] as any): undefined, timeout, responseType: ResponseType.Binary}) - return { - url: response.url, - method, - headers: response.headers, - body: [response.data], - statusCode: response.status, - statusMessage: (HTTP_STATUS as any)[response.status] - } as Response - }, - fetch: fetch as unknown as typeof window.fetch -} - -/** Runs the CLI command `esbuild [args]`. */ -export async function bundle(args: string[] = [], cwd?: string) { - console.info(`[TAURI] ${cwd? cwd: await appDir()}> esbuild ${args.join(" ")}`) - const opts = cwd? {cwd}: {} - const output = await Command.sidecar("bin/esbuild", [...args], opts).execute() - console.log(output.stdout || output.stderr) - if(!output.code) { - return output.stderr - } - else { - throw output.stderr - } -} - -/** Search using npm's registry API (https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md). Uses the registry API since the CLI doesn't support search qualifiers such as tags. */ -export async function search(text: string, params?: {size?: number, quality?: number, popularity?: number, maintenance?: number}, searchEndpoint="https://registry.npmjs.com/-/v1/search") { - const allParams = {text, ...{size: 250, ...params}} - const baseURL = new URL(searchEndpoint) - Object.entries(allParams).forEach(([k, v]) => v? baseURL.searchParams.append(k, v.toString()): null) - let from = 0 - let total = Number.POSITIVE_INFINITY - let objects: any[] = [] - let time = undefined - do { - let url = new URL(baseURL.href) - url.searchParams.set("from", String(from)) - const result = await window.fetch(baseURL) - if(result.ok) { - const body = await result.json() - from += params?.size ?? 250 - total = body.total - time = body.time - objects = objects.concat(body.objects) - } - else { - return new Error(`${result.status} ${result.statusText}`) - } - } while(from < total) - return {objects, total, time} -} - -/** Runs the CLI command `pnpm [commandArgs]`. */ -export async function pm(command: string, commandArgs: string[] = [], cwd?: string) { - // const defaultArgs = ["--reporter=ndjson"] - const cmdArgs = [command, ...commandArgs] - const opts = cwd? {cwd}: {} - console.info(`[TAURI] ${cwd? cwd: await appDir()}> bun ${cmdArgs.join(" ")}`) - const output = await Command.sidecar("bin/bun", cmdArgs, opts).execute() - console.log(output.stdout, output.stderr) - if(output.code) { - throw new Error(output.stderr) - } -} - -/** Get the names of all fonts installed on the user's system. */ -export function getSystemFonts() { - return invoke("get_system_fonts") -} - - - - -/** Create a new window. */ -export async function createWindow(url="index.html", options?: WindowOptions & {label?: string}) { - const allWindows = getAll() - const allLabels = allWindows.map(w => w.label) - const i = Math.max(...allLabels.map(l => parseInt(l)).filter(n => !Number.isNaN(n)), 1) + 1 - const existingWebview = WebviewWindow.getByLabel(options?.label ?? "") - if(existingWebview && !(await existingWebview.isVisible())) { - return existingWebview?.show() - } - else if(existingWebview && await existingWebview.isVisible()) { - await existingWebview.unminimize() - await existingWebview.setFocus() - } - else { - const webview = new WebviewWindow(options?.label ?? `${i}`, {url, ...options}) - return new Promise((resolve, reject) => { - webview.once("tauri://window-created", () => resolve(url)) - webview.once("tauri://error", e => reject(new Error((e as any).payload))) - }) - } -} - -export function setWindowCloseBehavior(behaviors: WindowCloseBehavior[], closeConfirm?: () => Promise) { - return - const webview = getCurrent() - console.log(webview) - for(const behavior of behaviors) { - if(behavior === "closeAllIfLastVisible") { - webview.onCloseRequested(async e => { - if(closeConfirm && !(await closeConfirm())) { - e.preventDefault() - return - } - const allWindows = getAll() - const visibilityList = await Promise.all(allWindows.map(w => w.isVisible())) - const isLast = !allWindows.some((w, i) => w.label !== webview.label && visibilityList[i]) - if(isLast) { - e.preventDefault() - exit(0) - } - }) - } - else if(behavior === "hideOnCloseUnlessLast") { - webview.onCloseRequested(async e => { - console.log(e) - if(closeConfirm && await closeConfirm()) { - e.preventDefault() - return - } - getAll().length > 1 && e.preventDefault() - webview.hide() - }) - } - else if(behavior === "closeOthersOnReload") { - window.addEventListener("beforeunload", e => { - getAll().filter(w => w.label !== webview.label).forEach(w => { - !WEBWRITER_ENVIRONMENT.dev && e.preventDefault() - w.close() - }) - }) - } - } -} - -export function getWindowLabel() { - return getCurrent().label -} \ No newline at end of file diff --git a/@webwriter/core/model/index.ts b/@webwriter/core/model/index.ts index 713e87a8..db14cfdf 100644 --- a/@webwriter/core/model/index.ts +++ b/@webwriter/core/model/index.ts @@ -1,4 +1,6 @@ export * from "./stores" export * from "./schemas" -export * from "./environment" +export {default as marshal} from "./marshal" +export * from "./clients" +export {default as clients} from "./clients" export * from "./clients" \ No newline at end of file diff --git a/test/specs/core/test-view.ts b/@webwriter/core/model/marshal/h5p.test.ts similarity index 100% rename from test/specs/core/test-view.ts rename to @webwriter/core/model/marshal/h5p.test.ts diff --git a/@webwriter/core/model/marshal/h5p.ts b/@webwriter/core/model/marshal/h5p.ts index 08f6677e..b21fe791 100644 --- a/@webwriter/core/model/marshal/h5p.ts +++ b/@webwriter/core/model/marshal/h5p.ts @@ -1,6 +1,5 @@ import {Node, Schema} from "prosemirror-model" -import { Environment } from "../environment" import {docToBundle} from "./html" import JSZip from "jszip" import {html, render} from "lit" @@ -396,9 +395,9 @@ export async function parse(data: string, schema: Schema) { } } -export async function serialize(explorable: Node, head: Node, bundle: Environment["bundle"], Path: Environment["Path"], FS: Environment["FS"]) { +export async function serialize(explorable: Node, head: Node) { - const {html, js, css} = await docToBundle(explorable, head, bundle, Path, FS) + const {html, js, css} = await docToBundle(explorable, head) const script = html.createElement("script") script.type = "text/javascript" diff --git a/@webwriter/core/model/marshal/html.test.ts b/@webwriter/core/model/marshal/html.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/marshal/html.ts b/@webwriter/core/model/marshal/html.ts index beb67073..e40073df 100644 --- a/@webwriter/core/model/marshal/html.ts +++ b/@webwriter/core/model/marshal/html.ts @@ -2,7 +2,6 @@ import {Node, DOMSerializer} from "prosemirror-model" import {Schema, DOMParser} from "prosemirror-model" import { EditorStateWithHead, PackageStore, createEditorState, headSchema, headSerializer } from '..' -import { Environment } from '../environment' import scopedCustomElementRegistry from "@webcomponents/scoped-custom-element-registry/src/scoped-custom-element-registry.js?raw" import { ParserSerializer } from './parserserializer' @@ -44,7 +43,7 @@ function createInitializerScript(id: string, tag: string, content: string) { ` } -export async function docToBundle(doc: Node, head: Node, bundle?: Environment["bundle"], Path?: Environment["Path"], FS?: Environment["FS"]) { +export async function docToBundle(doc: Node, head: Node) { let html = document.implementation.createHTMLDocument() const serializer = DOMSerializer.fromSchema(doc.type.schema) serializer.serializeFragment(doc.content, {document: html}, html.body) @@ -69,11 +68,6 @@ export async function docToBundle(doc: Node, head: Node, bundle?: Environment["b js = "" css = "" } - else if(bundle && Path && FS) { - const {bundleJS, bundleCSS} = await PackageStore.readBundle(importIDs, bundle, Path, FS, true) - js = bundleJS? scopedCustomElementRegistry + ";" + bundleJS: "" - css = bundleCSS - } else { const jsUrl = new URL("https://api.webwriter.app/ww/v1/_bundles") importIDs.forEach(id => jsUrl.searchParams.append("id", id)) @@ -190,8 +184,7 @@ export class HTMLParserSerializer extends ParserSerializer { async serializeToDOM(state: EditorStateWithHead) { - const envArgs = WEBWRITER_ENVIRONMENT.backend === "tauri"? [this.Environment.bundle, this.Environment.Path, this.Environment.FS] as any: [] - const {html, js, css} = await docToBundle(state.doc, state.head$.doc, ...envArgs) + const {html, js, css} = await docToBundle(state.doc, state.head$.doc) const script = html.createElement("script") script.type = "module" diff --git a/@webwriter/core/model/marshal/index.ts b/@webwriter/core/model/marshal/index.ts index f874ad3b..2ecd4871 100644 --- a/@webwriter/core/model/marshal/index.ts +++ b/@webwriter/core/model/marshal/index.ts @@ -2,7 +2,7 @@ import { HTMLParserSerializer } from "./html" import { ZipParserSerializer } from "./zip" import { MarkdownParserSerializer } from "./markdown" import { IpynbParserSerializer } from "./ipynb" -import { getFileExtension } from "../../utility" +import { getFileExtension } from "../utility" const formats = { "text/html": HTMLParserSerializer, diff --git a/@webwriter/core/model/marshal/ipynb.test.ts b/@webwriter/core/model/marshal/ipynb.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/marshal/markdown.test.ts b/@webwriter/core/model/marshal/markdown.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/marshal/parserserializer.test.ts b/@webwriter/core/model/marshal/parserserializer.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/marshal/parserserializer.ts b/@webwriter/core/model/marshal/parserserializer.ts index addaec61..fbf2c8a3 100644 --- a/@webwriter/core/model/marshal/parserserializer.ts +++ b/@webwriter/core/model/marshal/parserserializer.ts @@ -1,5 +1,4 @@ import { Schema } from "prosemirror-model" -import { Environment } from "../environment" import { EditorStateWithHead } from "../schemas" export interface ParserSerializer { @@ -12,7 +11,5 @@ export abstract class ParserSerializer { static readonly extensions: ReadonlyArray = [] static readonly mediaType: string - constructor(readonly Environment: Environment) {} - abstract parse(data: string, schema: Schema): Promise } \ No newline at end of file diff --git a/@webwriter/core/model/marshal/zip.test.ts b/@webwriter/core/model/marshal/zip.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/marshal/zip.ts b/@webwriter/core/model/marshal/zip.ts index 71dd1b3f..c4323832 100644 --- a/@webwriter/core/model/marshal/zip.ts +++ b/@webwriter/core/model/marshal/zip.ts @@ -69,11 +69,11 @@ export class ZipParserSerializer extends ParserSerializer { const zip = new JSZip() await zip.loadAsync(data) const htmlString = await zip.file("index.html")?.async("string") ?? "" - const htmlParserSerializer = new HTMLParserSerializer(this.Environment) + const htmlParserSerializer = new HTMLParserSerializer() return htmlParserSerializer.parse(htmlString, schema) } async serialize(state: EditorStateWithHead) { - const {html, js, css} = await docToBundle(state.doc, state.head$.doc, this.Environment.bundle, this.Environment.Path, this.Environment.FS) + const {html, js, css} = await docToBundle(state.doc, state.head$.doc) const zip = new JSZip() diff --git a/@webwriter/core/model/schemas/account.test.ts b/@webwriter/core/model/schemas/account.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/schemas/accounts.ts b/@webwriter/core/model/schemas/account.ts similarity index 73% rename from @webwriter/core/model/schemas/accounts.ts rename to @webwriter/core/model/schemas/account.ts index aaae0f9c..3e8bde62 100644 --- a/@webwriter/core/model/schemas/accounts.ts +++ b/@webwriter/core/model/schemas/account.ts @@ -1,40 +1,8 @@ import { z } from "zod"; -export type Account = NpmAccount | PocketbaseAccount | LLMAccount; - -export interface NpmAccount - extends z.infer<(typeof NpmAccount)["objectSchema"]> {} -export class NpmAccount { - static readonly key = "npm" as const; - - static objectSchema = z - .object({ - url: z.string().url(), - key: z.string().optional(), - }) - .transform((arg) => ({ - ...arg, - url: arg.url.endsWith("/") ? arg.url : arg.url + "/", - })); - - get authUrl() { - return `${this.url}` + (this.key ? `:_authToken=${this.key}` : ""); - } - - get id() { - return `${this.key}@${this.url}`; - } - - static schema = NpmAccount.objectSchema - .transform((x) => new NpmAccount(x)) - .or(z.instanceof(NpmAccount)); +export type Account = PocketbaseAccount | LLMAccount; - constructor( - value: z.input<(typeof NpmAccount)["objectSchema"]> | NpmAccount - ) { - return Object.assign(this, value); - } -} +export type AccountTypeId = (typeof PocketbaseAccount)["key"] | (typeof LLMAccount)["key"] | "file" export interface PocketbaseAccount extends z.infer<(typeof PocketbaseAccount)["objectSchema"]> {} diff --git a/@webwriter/core/model/schemas/contentexpression/index.grammar b/@webwriter/core/model/schemas/contentexpression.grammar similarity index 100% rename from @webwriter/core/model/schemas/contentexpression/index.grammar rename to @webwriter/core/model/schemas/contentexpression.grammar diff --git a/@webwriter/core/model/schemas/contentexpression.test.ts b/@webwriter/core/model/schemas/contentexpression.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/schemas/contentexpression/index.ts b/@webwriter/core/model/schemas/contentexpression.ts similarity index 98% rename from @webwriter/core/model/schemas/contentexpression/index.ts rename to @webwriter/core/model/schemas/contentexpression.ts index cbfd9706..7b4b08ab 100644 --- a/@webwriter/core/model/schemas/contentexpression/index.ts +++ b/@webwriter/core/model/schemas/contentexpression.ts @@ -1,8 +1,8 @@ import {z} from "zod" import {Schema} from "prosemirror-model" -import {parser} from "./index.grammar" -import { filterObject } from "../../../utility" +import {parser} from "./contentexpression.grammar" +import { filterObject } from "../utility" function treeLog(tree: any, expr?: string) { let depth = -1 diff --git a/@webwriter/core/model/schemas/valuedefinition/cssproperty2.grammar b/@webwriter/core/model/schemas/cssvalue.grammar similarity index 99% rename from @webwriter/core/model/schemas/valuedefinition/cssproperty2.grammar rename to @webwriter/core/model/schemas/cssvalue.grammar index 4d76b3b1..07e837f5 100644 --- a/@webwriter/core/model/schemas/valuedefinition/cssproperty2.grammar +++ b/@webwriter/core/model/schemas/cssvalue.grammar @@ -1,4 +1,4 @@ -@top PropertyExpression { expression } +@top CSSValue { expression } @precedence {expr @left} diff --git a/@webwriter/core/model/schemas/cssvalue.test.ts b/@webwriter/core/model/schemas/cssvalue.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/schemas/cssvalue.ts b/@webwriter/core/model/schemas/cssvalue.ts new file mode 100644 index 00000000..9db08434 --- /dev/null +++ b/@webwriter/core/model/schemas/cssvalue.ts @@ -0,0 +1,2052 @@ +import Color from "colorjs.io" +import {parser} from "./cssvalue.grammar" +import { MediaType } from "#model" +import { CSSValueDefinition, treeLog } from "./cssvaluedefinition" + + +function cssFunc(name: string, args: (CSSStyleValue | string | undefined)[], separator=" ") { + return `${name}(${args.filter(a=>a).map(a => a!.toString()).join(separator)})` +} + +function parseCssFunc(text: string, separator: string | RegExp=/\s+/): {name: string, args: string[]} { + const [name, rawArgs] = text.slice(0, -1).split("(") + const args = rawArgs.split(separator).map(arg => arg.trim()) + return {name, args} +} + +function parseLengthOrPercentage(text: string) { + if(text.includes("%")) { + return CSSPercentageValue.parse(text) + } + else { + return CSSLengthValue.parse(text) + } +} + +function parseAngleOrPercentage(text: string) { + if(text.includes("%")) { + return CSSPercentageValue.parse(text) + } + else { + return CSSAngleValue.parse(text) + } +} + +// BASIC TYPES //////////////////////////////////////////////////////////////// + +export class CSSStringValue implements CSSStyleValue { + + value: string + + constructor(value: string) { + this.value = value + } + + toString() { + return '"' + this.value + '"' + } + + static parse(cssText: string) { + if(/(".*")|('.*')/.test(cssText)) { + return new CSSStringValue(cssText.slice(1, -1)) + } + else throw Error("Quotes are missing from CSS string") + } +} + +export class CSSColorValue implements CSSStyleValue { + + static systemColors = ["AccentColor", "AccentColorText", "ActiveText", "ButtonBorder", "ButtonFace", "ButtonText", "Canvas", "CanvasText", "Field", "FieldText", "GrayText", "Highlight", "HighlightText", "LinkText", "Mark", "MarkText", "SelectedItem", "SelectedItemText", "VisitedText"] as const + + static deprecatedSystemColors = ["ActiveBorder", "ActiveCaption", "AppWorkspace", "Background", "ButtonHighlight", "ButtonShadow", "CaptionText", "InactiveBorder", "InactiveCaption", "InactiveCaptionText", "InfoBackground", "InfoText", "Menu", "MenuText", "Scrollbar", "ThreeDDarkShadow", "ThreeDFace", "ThreeDHighlight", "ThreeDLightShadow", "ThreeDShadow", "Window", "WindowFrame", "WindowText"] as const + + #color: Color | typeof CSSColorValue["systemColors"][number] | typeof CSSColorValue["deprecatedSystemColors"][number] + + get value() { + return this.toString() + } + + constructor(color: Color | typeof CSSColorValue["systemColors"][number] | typeof CSSColorValue["deprecatedSystemColors"][number]) { + this.#color = color + } + + toString(options?: any) { + return (this.#color.toString as any)(options) + } + + static parse(cssText: string) { + if(this.systemColors.includes(cssText as any) || this.deprecatedSystemColors.includes(cssText as any)) { + return new CSSColorValue(cssText as any) + } + else { + return new CSSColorValue(new (Color as any)(cssText)) + } + + } +} + +export class CSSCustomIdentValue implements CSSStyleValue { + constructor( + readonly value: string + ) {} + + toString() { + return this.value + } + + static parse(cssText: string) { + return new this(cssText) + } +} + +export class CSSDashedIdentValue implements CSSStyleValue { + constructor( + readonly value: string + ) {} + + toString() { + return `--${this.value}` + } + + static parse(cssText: string) { + return new this(cssText.slice(2)) + } +} + +export class CSSRatioValue implements CSSStyleValue { + constructor( + readonly a: number, + readonly b: number + ) {} + + toString() { + return `${this.a}/${this.b}` + } + + static parse(cssText: string) { + const [a, b] = cssText.split("/").map(part => part.trim()) + return new this(parseInt(a), parseInt(b)) + } +} + +export class CSSPositionValue implements CSSStyleValue { + constructor( + readonly originX: "left" | "center" | "right" = "center", + readonly offsetX: CSSPercentageValue | CSSLengthValue = new CSSPercentageValue(0), + readonly originY: "top" | "center" | "bottom" = "center", + readonly offsetY: CSSPercentageValue | CSSLengthValue = new CSSPercentageValue(0) + ) {} + + toString() { + return `${this.originX} ${this.offsetX} ${this.originY} ${this.offsetY}` + } + + static parse(text: string) { + const args = text.split(/\s+/) + if(args.length === 1 && ["left", "center", "right"].includes(args[0])) { + return new this(args[0] as any, undefined, undefined, undefined) + } + else if(args.length === 1 && ["top", "center", "bottom"].includes(args[0])) { + return new this(undefined, undefined, args[0] as any, undefined) + } + else if(args.length === 1) { + return new this("left", parseLengthOrPercentage(args[0]), args[0] as any, undefined) + } + else if(args.length === 2) { + const originX = ["left", "center", "right"].includes(args[0])? args[0]: undefined + const offsetX = ["left", "center", "right"].includes(args[0])? undefined: parseLengthOrPercentage(args[0]) + const originY = ["top", "center", "bottom"].includes(args[1])? args[1]: undefined + const offsetY = ["top", "center", "bottom"].includes(args[1])? undefined: parseLengthOrPercentage(args[1]) + return new this(originX as any, offsetX, originY as any, offsetY) + } + else if(args.length === 4) { + const originX = ["left", "center", "right"].includes(args[0]) && !["left", "center", "right"].includes(args[2])? args[0]: args[2] + const offsetX = parseLengthOrPercentage(args[1]) + const originY = ["top", "center", "bottom"].includes(args[0]) && !["top", "center", "bottom"].includes(args[2])? args[0]: args[2] + const offsetY = parseLengthOrPercentage(args[3]) + return new this(originX as any, offsetX, originY as any, offsetY) + } + else throw Error(`Invalid number of arguments`) + } +} + +// NUMERIC TYPES ////////////////////////////////////////////////////////////// + +export class CSSMathValue extends window.CSSMathValue { + static parse(text: string): CSSMathValue { + return (window.CSSMathValue as any).parse(`calc(${text})`) + } +} + +CSSMathValue.parse + +export class CSSPercentageValue extends CSSUnitValue { + + constructor(value: number) { + super(value, "percent") + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(unit === "number") { + return new CSSPercentageValue(value * 100) + } + else if(unit !== "percent") { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSPercentageValue(value) + } + } +} + +export class CSSIntegerValue extends CSSUnitValue { + + constructor(value: number) { + super(value, "number") + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new CSSIntegerValue(0) + } + else if(unit !== "number") { + throw TypeError(`Invalid unit: ${unit}`) + } + else if(!Number.isInteger(value)) { + throw TypeError(`Not an integer: ${value}`) + } + else { + return new CSSIntegerValue(value) + } + } +} + +export class CSSNumberValue extends CSSUnitValue { + + constructor(value: number) { + super(value, "number") + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new CSSNumberValue(0) + } + else if(unit !== "number") { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSNumberValue(value) + } + } +} + +export class CSSFlexValue extends CSSUnitValue { + + constructor(value: number) { + super(value, "fr") + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new CSSFlexValue(0) + } + else if(unit !== "fr") { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSFlexValue(value) + } + } +} + +export class CSSLengthValue extends CSSUnitValue { + + static units = ["cap", "ch", "em", "ex", "ic", "lh", "rcap", "rch", "rem", "rex", "ric", "rlh", "vh", "vw", "vmax", "vmin", "vb", "vi", "cqw", "cqh", "cqi", "cqb", "cqmin", "cqmax", "px", "cm", "mm", "Q", "in", "pc", "pt"] as const + + constructor(value: number, unit: typeof CSSLengthValue["units"][number]) { + super(value, unit) + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new this(0, this.units[0]) + } + else if(!CSSLengthValue.units.includes(unit as any)) { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSLengthValue(value, unit as typeof CSSLengthValue["units"][number]) + } + } +} + +export class CSSAngleValue extends CSSUnitValue { + + static units = ["deg", "grad", "rad", "turn"] as const + + constructor(value: number, unit: typeof CSSAngleValue["units"][number]) { + super(value, unit) + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new this(0, this.units[0]) + } + else if(!CSSAngleValue.units.includes(unit as any)) { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSAngleValue(value, unit as typeof CSSAngleValue["units"][number]) + } + } +} + +export class CSSTimeValue extends CSSUnitValue { + + static units = ["s", "ms"] as const + + constructor(value: number, unit: typeof CSSTimeValue["units"][number]) { + super(value, unit) + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new this(0, this.units[0]) + } + else if(!CSSTimeValue.units.includes(unit as any)) { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSTimeValue(value, unit as typeof CSSTimeValue["units"][number]) + } + } +} + +export class CSSFrequencyValue extends CSSUnitValue { + + static units = ["Hz", "kHz"] as const + + constructor(value: number, unit: typeof CSSFrequencyValue["units"][number]) { + super(value, unit) + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new this(0, this.units[0]) + } + else if(!CSSFrequencyValue.units.includes(unit as any)) { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSFrequencyValue(value, unit as typeof CSSFrequencyValue["units"][number]) + } + } +} + +export class CSSResolutionValue extends CSSUnitValue { + + static units = ["dpi", "dpcm", "dppx", "x"] as const + + constructor(value: number, unit: typeof CSSResolutionValue["units"][number]) { + super(value, unit) + } + + static parse(text: string) { + const {value, unit} = CSSNumericValue.parse(text) as CSSUnitValue + if(value === 0 && unit === "number") { + return new this(0, this.units[0]) + } + else if(!CSSResolutionValue.units.includes(unit as any)) { + throw TypeError(`Invalid unit: ${unit}`) + } + else { + return new CSSResolutionValue(value, unit as typeof CSSResolutionValue["units"][number]) + } + } +} + +// FUNCTION TYPES ///////////////////////////////////////////////////////////// + +export class CSSTransformValue extends window.CSSTransformValue { + static parse(a: string, b?: string) { // @ts-ignore + return super.parse(b? a: "transform", b ?? a) as CSSTransformValue + } +} + +export class CSSColorMixValue implements CSSStyleValue { + colorSpace: "srgb" |"srgb-linear" | "display-p3" | "a98-rgb" | "prophoto-rgb" | "rec2020" | "lab" | "oklab" | "xyz" |"xyz-d50" | "xyz-d65" | "hsl" | "hwb" | "lch" | "oklch" + hueInterpolation?: "shorter" | "longer" | "increasing" | "decreasing" + + colorA: CSSColorValue + amountA?: CSSUnitValue + colorB: CSSColorValue + amountB?: CSSUnitValue + + constructor(colorSpace: CSSColorMixValue["colorSpace"], colorA: CSSColorValue, colorB: CSSColorValue, amountA?: CSSPercentageValue, amountB?: CSSPercentageValue, hueInterpolation?: CSSColorMixValue["hueInterpolation"]) { + this.colorSpace = colorSpace + this.colorA = colorA + this.colorB = colorB + this.amountA = amountA + this.amountB = amountB + this.hueInterpolation = hueInterpolation + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "color-mix") throw TypeError("Invalid function name") + const [interpolationMethod, stopA, stopB] = args + const [_, colorSpace, hueInterpolation, __] = interpolationMethod.split(/\s+/) + if(_ !== "in" || __ !== undefined && __ !== "hue" || !["srgb", "srgb-linear", "display-p3", "a98-rgb", "prophoto-rgb", "rec2020", "lab", "oklab", "xyz", "xyz-d50", "xyz-d65", "hsl", "hwb", "lch", "oklch"].includes(colorSpace) || hueInterpolation && !["shorter", "longer", "increasing", "decreasing"].includes(hueInterpolation)) throw TypeError("Invalid argument syntax") + const [colorA, amountA] = (stopA ?? "").split(/\s+/) + const [colorB, amountB] = (stopB ?? "").split(/\s+/) + return new CSSColorMixValue( + colorSpace as any, + CSSColorValue.parse(colorA), + CSSColorValue.parse(colorB), + CSSPercentageValue.parse(amountA), + CSSPercentageValue.parse(amountB), + hueInterpolation as any + ) + + } + + toString() { + const interpolationMethod = `in ${this.colorSpace}${this.hueInterpolation? ` ${this.hueInterpolation} hue` :""}` + const a = `${this.colorA}${this.amountA? ` ${this.amountA}`: ""}` + const b = `${this.colorB}${this.amountB? ` ${this.amountB}`: ""}` + return cssFunc("color-mix", [interpolationMethod, a, b], ",") + } +} + +export class CSSLightDarkValue implements CSSStyleValue { + constructor(readonly a: CSSColorValue, readonly b: CSSColorValue) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "light-dark") throw TypeError("Invalid function name") + return new CSSLightDarkValue(CSSColorValue.parse(args[0]), CSSColorValue.parse(args[1])) + } + + toString() { + return cssFunc("light-dark", [this.a, this.b], ",") + } +} + +export class CSSDeviceCmykValue implements CSSStyleValue { + c: CSSPercentageValue + m: CSSPercentageValue + y: CSSPercentageValue + k: CSSPercentageValue + a?: CSSPercentageValue + fallback?: CSSColorValue + + constructor(c: CSSPercentageValue, m: CSSPercentageValue, y: CSSPercentageValue, k: CSSPercentageValue, a?: CSSPercentageValue) { + this.c = c + this.m = m + this.y = y + this.k = k + this.a = a + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "light-dark") throw TypeError("Invalid function name") + else if(args.length === 1 || args.length === 2) { + const [cmyk, a] = args[0].split("/") + const [c, m, y, k] = cmyk.split(/\s+/) + return new CSSDeviceCmykValue(CSSPercentageValue.parse(c), CSSPercentageValue.parse(m), CSSPercentageValue.parse(y), CSSPercentageValue.parse(k), a? CSSPercentageValue.parse(a): undefined) + } + else if(args.length === 4) { + return new CSSDeviceCmykValue(...args.map(arg => CSSPercentageValue.parse(arg)) as [CSSPercentageValue, CSSPercentageValue, CSSPercentageValue, CSSPercentageValue]) + } + else throw TypeError("Invalid number of arguments") + } + + toString() { + return cssFunc("device-cmyk", [this.c, this.m, this.y, this.k, this.a]) + } +} + +export abstract class CSSImageValue implements CSSStyleValue { + static parse(text: string) { + const {name} = parseCssFunc(text) + if(["url", "src"].includes(name)) { + return CSSUrlValue.parse(text) + } + else if(name === "element") { + return CSSElementValue.parse(text) + } + else if(name === "image-set") { + return CSSImageSetValue.parse(text) + } + else if(name === "cross-fade") { + return CSSCrossFadeValue.parse(text) + } + else if(["linear-gradient", "radial-gradient", "conic-gradient"].some(s => name.endsWith(s))) { + return CSSGradientValue.parse(text) + } + else throw TypeError("Invalid function name") + } +} + +export abstract class CSSGradientValue extends CSSImageValue { + + static parse(text: string): CSSLinearGradientValue | CSSRadialGradientValue | CSSConicGradientValue { + const {name} = parseCssFunc(text) + if(name.endsWith("linear-gradient")) { + return CSSLinearGradientValue.parse(text) + } + else if(name.endsWith("radial-gradient")) { + return CSSRadialGradientValue.parse(text) + } + else if(name.endsWith("conic-gradient")) { + return CSSConicGradientValue.parse(text) + } + else throw TypeError("Invalid function name") + } +} + +export class CSSLinearGradientValue extends CSSGradientValue { + constructor( + readonly stops: ({color: CSSColorValue, a?: CSSPercentageValue | CSSLengthValue, b?: CSSPercentageValue | CSSLengthValue} | {hint: CSSPercentageValue | CSSLengthValue})[], + readonly repeating = false, + readonly to?: CSSAngleValue | "left" | "right" | "top" | "bottom" | "top left" | "top right" | "bottom left" | "bottom right", + readonly colorSpace: "srgb" |"srgb-linear" | "display-p3" | "a98-rgb" | "prophoto-rgb" | "rec2020" | "lab" | "oklab" | "xyz" |"xyz-d50" | "xyz-d65" | "hsl" | "hwb" | "lch" | "oklch" = "oklab", + readonly hueInterpolation?: "shorter" | "longer" | "increasing" | "decreasing" + ) {super()} + + toString() { + const firstArg = [ + this.colorSpace + ? `in ${this.colorSpace}` + this.hueInterpolation? ` ${this.hueInterpolation} hue`: "" + : "", + this.to instanceof CSSAngleValue + ? this.to + : (this.to? "to " + this.to: ""), + ].join(" ").trim() + return cssFunc(this.repeating? "repeating-linear-gradient": "linear-gradient", [firstArg, ...this], ",") + } + + private static parseStop(text: string) { + const [colorOrHint, a, b] = text.split(/\s+/) + let isColor = false + try { + CSSColorValue.parse(colorOrHint) + isColor = true + } catch {} + if(isColor && !a) { + return {color: CSSColorValue.parse(colorOrHint)} + } + else if(isColor && a) { + return { + color: CSSColorValue.parse(colorOrHint), + a: parseLengthOrPercentage(a) + } + } + else if(isColor && b) { + return { + color: CSSColorValue.parse(colorOrHint), + a: parseLengthOrPercentage(a), + b: parseLengthOrPercentage(a) + } + } + else { + return {hint: parseLengthOrPercentage(colorOrHint)} + } + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + let repeating = name === "repeating-linear-gradient" + let hasInterpolationArg = true + try { + this.parseStop(args[0]) + hasInterpolationArg = false + } catch {} + if(!["linear-gradient", "repeating-linear-gradient"].includes(name)) throw Error("Invalid function name") + else if(!args.length) throw Error("Invalid arguments") + else { + let to, colorSpace, hueInterpolation + if(hasInterpolationArg) { + const parts = args[0].split(/\s+/) + const anglePart = parts.find(part => ["deg", "grad", "rad", "turn"].some(suffix => part.endsWith(suffix))) + const angle = anglePart? CSSAngleValue.parse(anglePart): undefined + const sideOrCorner = parts.filter(part => ["left", "right", "top", "bottom"].includes(part)).join(" ") + to = angle? angle: sideOrCorner as Exclude + if(parts.includes("in")) { + colorSpace = parts[parts.indexOf("in") + 1] as any + } + if(parts.includes("hue")) { + hueInterpolation = parts[parts.indexOf("hue") - 1] as any + } + } + let stops = args.slice(hasInterpolationArg? 1: 0).map(arg => this.parseStop(arg)) + return new this(stops, repeating, to, colorSpace, hueInterpolation) + } + } + + *[Symbol.iterator]() { + for(const value of this.stops) { + yield value + } + } + +} + +export class CSSRadialGradientValue extends CSSGradientValue { + constructor( + readonly stops: ({color: CSSColorValue, a?: CSSPercentageValue | CSSLengthValue} | {hint: CSSPercentageValue | CSSLengthValue})[], + readonly repeating = false, + readonly shape?: "circle" | "ellipse", + readonly size?: "closest-corner" | "closest-side" | "farthest-corner" | "farthest-side" | CSSLengthValue | [CSSLengthValue | CSSPercentageValue, CSSLengthValue | CSSPercentageValue], + readonly at?: CSSPositionValue + ) {super()} + + toString() { + const firstArg = [ + this.shape?.toString(), + this.size?.toString(), + this.at? "at " + this.at: undefined, + ].filter(arg => arg).join(" ").trim() + return cssFunc(this.repeating? "repeating-radial-gradient": "radial-gradient", [firstArg, ...this], ",") + } + + private static parseStop(text: string) { + const [colorOrHint, a] = text.split(/\s+/) + let isColor = false + try { + CSSColorValue.parse(colorOrHint) + isColor = true + } catch {} + if(isColor && !a) { + return {color: CSSColorValue.parse(colorOrHint)} + } + else if(isColor && a) { + return { + color: CSSColorValue.parse(colorOrHint), + a: parseLengthOrPercentage(a) + } + } + else { + return {hint: parseLengthOrPercentage(colorOrHint)} + } + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + let repeating = name === "repeating-radial-gradient" + let hasInterpolationArg = true + try { + this.parseStop(args[0]) + hasInterpolationArg = false + } catch {} + if(!["radial-gradient", "repeating-radial-gradient"].includes(name)) throw Error("Invalid function name") + else if(!args.length) throw Error("Invalid arguments") + else { + let shape, size, at + if(hasInterpolationArg) { + const parts = args[0].split(/\s+/) + shape = parts.find(v => v === "circle" || v === "ellipse") + if(parts.includes("at")) { + at = CSSPositionValue.parse(parts[parts.indexOf("at") + 1]) + } + let radialSizeParts = parts + .slice(0, parts.indexOf("at")) + .filter(v => v !== "circle" && v !== "ellipse") + if(radialSizeParts.length === 2) { + size = [ + parseLengthOrPercentage(radialSizeParts[0]), + parseLengthOrPercentage(radialSizeParts[1]) + ] as [CSSLengthValue | CSSPercentageValue, CSSLengthValue | CSSPercentageValue] + } + else if(["closest-corner", "closest-side", "farthest-corner", "farthest-side"].includes(radialSizeParts[0])) { + size = radialSizeParts[0] as "closest-corner" | "closest-side" | "farthest-corner" | "farthest-side" + } + else { + size = CSSLengthValue.parse(radialSizeParts[0]) + } + } + let stops = args.slice(hasInterpolationArg? 1: 0).map(arg => this.parseStop(arg)) + return new this(stops, repeating, shape, size, at) + } + } + + *[Symbol.iterator]() { + for(const value of this.stops) { + yield value + } + } +} + +export class CSSConicGradientValue extends CSSGradientValue { + constructor( + readonly stops: ({color: CSSColorValue, a: CSSAngleValue | CSSPercentageValue, b?: CSSAngleValue | CSSPercentageValue} | {hint: CSSPercentageValue | CSSAngleValue})[], + readonly repeating = false, + readonly from?: CSSAngleValue, + readonly at?: CSSPositionValue, + readonly colorSpace: "srgb" |"srgb-linear" | "display-p3" | "a98-rgb" | "prophoto-rgb" | "rec2020" | "lab" | "oklab" | "xyz" |"xyz-d50" | "xyz-d65" | "hsl" | "hwb" | "lch" | "oklch" = "oklab", + readonly hueInterpolation?: "shorter" | "longer" | "increasing" | "decreasing" + ) {super()} + + toString() { + const firstArg = [ + this.from? "from " + this.from: "", + this.at? "at " + this.at: "", + this.colorSpace + ? `in ${this.colorSpace}` + this.hueInterpolation? ` ${this.hueInterpolation} hue`: "" + : "", + ].join(" ").trim() + return cssFunc(this.repeating? "repeating-conic-gradient": "conic-gradient", [firstArg, ...this], ",") + } + + private static parseStop(text: string) { + const [colorOrHint, a, b] = text.split(/\s+/) + let isColor = false + try { + CSSColorValue.parse(colorOrHint) + isColor = true + } catch {} + if(isColor && a && !b) { + return { + color: CSSColorValue.parse(colorOrHint), + a: parseAngleOrPercentage(a) + } + } + else if(isColor && b) { + return { + color: CSSColorValue.parse(colorOrHint), + a: parseAngleOrPercentage(a), + b: parseAngleOrPercentage(a) + } + } + else { + return {hint: parseAngleOrPercentage(colorOrHint)} + } + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + let repeating = name === "repeating-conic-gradient" + let hasInterpolationArg = true + try { + this.parseStop(args[0]) + hasInterpolationArg = false + } catch {} + if(!["conic-gradient", "repeating-conic-gradient"].includes(name)) throw Error("Invalid function name") + else if(!args.length) throw Error("Invalid arguments") + else { + let from, at, colorSpace, hueInterpolation + if(hasInterpolationArg) { + const parts = args[0].split(/\s+/) + if(parts.includes("from")) { + CSSAngleValue.parse(parts[parts.indexOf("from") + 1]) + } + if(parts.includes("at")) { + CSSAngleValue.parse(parts[parts.indexOf("at") + 1]) + } + if(parts.includes("in")) { + colorSpace = parts[parts.indexOf("in") + 1] as any + } + if(parts.includes("hue")) { + hueInterpolation = parts[parts.indexOf("hue") - 1] as any + } + } + let stops = args.slice(hasInterpolationArg? 1: 0).map(arg => this.parseStop(arg)) + return new this(stops, repeating, from, at, colorSpace, hueInterpolation) + } + } + + *[Symbol.iterator]() { + for(const value of this.stops) { + yield value + } + } +} + +export class CSSFilterValue implements CSSStyleValue {} +export class CSSBlurValue extends CSSFilterValue { + radius?: CSSLengthValue + + constructor(radius?: CSSLengthValue) { + super() + this.radius = radius + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "blur") throw TypeError("Invalid function name") + const radius = CSSLengthValue.parse(args.join("")) + return new CSSBlurValue(radius) + } + + toString() { + return cssFunc("blur", [this.radius]) + } +} +export class CSSBrightnessValue extends CSSFilterValue { + amount?: CSSPercentageValue + + constructor(amount?: CSSPercentageValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "brightness") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSBrightnessValue(amount) + } + + toString() { + return cssFunc("brightness", [this.amount]) + } +} + +export class CSSContrastValue extends CSSFilterValue { + amount?: CSSUnitValue + + constructor(amount?: CSSUnitValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "contrast") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSContrastValue(amount) + } + + toString() { + return cssFunc("contrast", [this.amount]) + } +} + +export class CSSDropShadowValue extends CSSFilterValue { + + constructor( + readonly offsetX: CSSLengthValue, + readonly offsetY: CSSLengthValue, + readonly color?: CSSColorValue, + readonly standardDeviation?: CSSLengthValue + ) {super()} + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "drop-shadow") throw TypeError("Invalid function name") + let color, hasColor = false + try { + CSSColorValue.parse(args[0]) + hasColor = true + } catch {} + if(hasColor) { + color = CSSColorValue.parse(args[0]) + } + const [offsetX, offsetY, standardDeviation] = args + .slice(hasColor? 1: 0) + .map(arg => arg? CSSLengthValue.parse(arg): undefined) + .filter(arg => arg) + return new this(offsetX!, offsetY!, color, standardDeviation) + } + + toString() { + return cssFunc("drop-shadow", [this.color, this.offsetX, this.offsetY, this.standardDeviation]) + } +} + +export class CSSGrayscaleValue extends CSSFilterValue { + amount?: CSSUnitValue + + constructor(amount?: CSSUnitValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "grayscale") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSGrayscaleValue(amount) + } + + toString() { + return cssFunc("grayscale", [this.amount]) + } +} + +export class CSSHueRotateValue extends CSSFilterValue { + angle?: CSSAngleValue + + constructor(angle?: CSSAngleValue) { + super() + this.angle = angle + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "hue-rotate") throw TypeError("Invalid function name") + const angle = CSSAngleValue.parse(args.join("")) + return new CSSBlurValue(angle) + } + + toString() { + return cssFunc("hue-rotate", [this.angle]) + } +} + +export class CSSInvertValue extends CSSFilterValue { + amount?: CSSPercentageValue + + constructor(amount?: CSSPercentageValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "invert") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSInvertValue(amount) + } + + toString() { + return cssFunc("invert", [this.amount]) + } +} +export class CSSOpacityValue extends CSSFilterValue { + amount?: CSSPercentageValue + + constructor(amount?: CSSPercentageValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "opacity") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSOpacityValue(amount) + } + + toString() { + return cssFunc("opacity", [this.amount]) + } +} + +export class CSSSepiaValue extends CSSFilterValue { + amount?: CSSPercentageValue + + constructor(amount?: CSSPercentageValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "sepia") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSSepiaValue(amount) + } + + toString() { + return cssFunc("sepia", [this.amount]) + } +} + +export class CSSSaturateValue extends CSSFilterValue { + amount?: CSSPercentageValue + + constructor(amount?: CSSPercentageValue) { + super() + this.amount = amount + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "saturate") throw TypeError("Invalid function name") + const arg = args.join("") + const amount = CSSPercentageValue.parse(arg) + return new CSSSaturateValue(amount) + } + + toString() { + return cssFunc("saturate", [this.amount]) + } +} + +type CSSSymbol = { + type: "cyclic" | "numeric" | "alphabetic" | "symbolic" | "fixed" +} + +export class CSSCounterValue implements CSSStyleValue { + name: string + style?: string | CSSSymbolsValue | "none" | "disc" | "circle" | "square" | "decimal" | "cjk-decimal" | "decimal-leading-zero" | "lower-roman" | "upper-roman" | "lower-greek" | "lower-alpha" | "upper-alpha" | "arabic-indic" | "armenian" | "cambodian" | "cjk-earthly-branch" | "cjk-heavenly-stem" | "cjk-ideographic" | "devanagari" | "ethiopic-numeric" | "georgian" | "gujarati" | "gurmukhi" | "hebrew" | "hiragana" | "hiragana-iroha" | "japanese-formal" | "japanese-informal" | "kannada" | "katakana" | "katakana-iroha" | "korean-hangul-formal" | "korean-hanja-informal" | "lao" | "lower-armenian" | "malayalam" | "mongolian" | "myanmar" | "oriya" | "persian" | "simp-chinese-formal" | "simp-chinese-informal" | "tamil" | "telugu" | "thai" | "tibetan" | "trad-chinese-formal" | "trad-chinese-informal" | "upper-armenian" | "disclosure-open" | "disclosure-closed" + separator?: string + + isCounters() { + return !!this.separator + } + + constructor(name: string, separator?: string, style?: CSSCounterValue["style"]) { + this.name = name + this.separator = separator + this.style = style + } + + static parseCounterStyle(text: string) { + let counterStyle: CSSCounterValue["style"] + if(CSSSymbolsValue.is(text)) { + counterStyle = CSSSymbolsValue.parse(text) + } + else if(["none", "disc", "circle", "square", "decimal", "cjk-decimal", "decimal-leading-zero", "lower-roman", "upper-roman", "lower-greek", "lower-alpha", "upper-alpha", "arabic-indic", "armenian", "cambodian", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", "devanagari", "ethiopic-numeric", "georgian", "gujarati", "gurmukhi", "hebrew", "hiragana", "hiragana-iroha", "japanese-formal", "japanese-informal", "kannada", "katakana", "katakana-iroha", "korean-hangul-formal", "korean-hanja-informal", "lao", "lower-armenian", "malayalam", "mongolian", "myanmar", "oriya", "persian", "simp-chinese-formal", "simp-chinese-informal", "tamil", "telugu", "thai", "tibetan", "trad-chinese-formal", "trad-chinese-informal", "upper-armenian", "disclosure-open", "disclosure-closed", undefined].includes(text)) { + counterStyle = text + } + return counterStyle + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "counter" && name !== "counters") throw TypeError("Invalid function name") + else if(args.length === 1 && name === "counter") { + return new CSSCounterValue(args[0]) + } + else if(args.length === 2 && name === "counter") { + return new CSSCounterValue(args[0], args[1]) + } + else if(args.length === 2 && name === "counters") { + const counterStyle = this.parseCounterStyle(args[1]) + return new CSSCounterValue(args[0], undefined, counterStyle) + } + else if(args.length === 3 && name === "counters") { + const counterStyle = this.parseCounterStyle(args[1]) + return new CSSCounterValue(args[0], args[1], counterStyle) + } + else throw Error("Invalid number of arguments for counter or counters.") + } + + toString() { + return this.separator? cssFunc("counters", [this.name, this.separator, this.style]): cssFunc("counter", [this.name, this.style], ",") + } +} + +export class CSSSymbolsValue implements CSSStyleValue { + type: "cyclic" | "numeric" | "alphabetic" | "symbolic" | "fixed" = "symbolic" + #values: (CSSStringValue | CSSImageValue)[] = [] + + constructor(values: CSSStyleValue[], type: CSSSymbolsValue["type"] = "symbolic") { + if(values.length < 1) { + throw TypeError("CSSSymbolsValue needs at least one value") + } + this.#values = values + this.type = type + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "symbols") throw TypeError("Invalid function name") + else if(["cyclic", "numeric", "alphabetic", "symbolic", "fixed"].includes(args[0])) { + return new CSSSymbolsValue(args.slice(1), args[0] as CSSSymbolsValue["type"]) + } + else if(args.every(arg => arg.startsWith("'") || arg.startsWith('"'))) { + return new CSSSymbolsValue(args) + } + else throw Error("Invalid arguments for symbols") + } + + static is(text: string) { + try { + this.parse(text) + return true + } catch {return false} + } + + toString() { + return cssFunc("symbols", [this.type, ...this]) + } + + *[Symbol.iterator]() { + for(const value of this.#values) { + yield value + } + } +} + + +export class CSSCircleValue implements CSSStyleValue { + r?: CSSLengthValue | CSSPercentageValue | "closest" | "farthest" + position?: CSSPositionValue + + constructor(r?: CSSLengthValue | "closest" | "farthest", position?: CSSPositionValue) { + this.r = r + this.position = position + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, "at") + if(name !== "circle") throw TypeError("Invalid function name") + else if(args.length === 2) { + return new this( + ["closest", "farthest"].includes(args[0]) + ? args[0] as "closest" | "farthest" + : parseLengthOrPercentage(args[0]), + CSSPositionValue.parse(args[1]) + ) + } + else if(args.length === 1 && text.includes("at ")) { + return new this(undefined, CSSPositionValue.parse(args[1])) + } + else if(args.length === 1) { + return new this(["closest", "farthest"].includes(args[0])? args[0] as "closest" | "farthest": CSSLengthValue.parse(args[0])) + } + else { + throw TypeError("Invalid arguments") + } + } + + toString() { + const r = this.r? `${this.r}`: "" + const position = this.position? `at ${this.position}`: "" + return cssFunc("circle", [r, position]) + } +} + +export class CSSEllipseValue implements CSSStyleValue { + r1?: CSSLengthValue | CSSPercentageValue | "closest-corner" | "closest-side" | "farthest-corner" | "farthest-side" + r2?: CSSLengthValue | CSSPercentageValue | "closest-corner" | "closest-side" | "farthest-corner" | "farthest-side" + position?: CSSPositionValue + + constructor(r1?: CSSEllipseValue["r1"], r2?: CSSEllipseValue["r2"], position?: CSSPositionValue) { + this.r1 = r1 + this.r2 = r2 + this.position = position + } + + static parseRadialExtent(text: string) { + if(["closest-corner", "closest-side", "farthest-corner", "farthest-side"].includes(text)) { + return text as "closest-corner" | "closest-side" | "farthest-corner" | "farthest-side" + } + else { + return parseLengthOrPercentage(text) + } + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text, "at") + if(name !== "circle") throw TypeError("Invalid function name") + else if(args.length === 2) { + const [r1, r2] = args[0].split(/\s+/).map(r => r? this.parseRadialExtent(r): undefined) + return new this(r1, r2 ?? r1, CSSPositionValue.parse(args[1])) + } + else if(args.length === 1 && text.includes("at ")) { + return new this(undefined, undefined, CSSPositionValue.parse(args[1])) + } + else if(args.length === 1) { + const [r1, r2] = args[0].split(/\s+/).map(r => r? this.parseRadialExtent(r): undefined) + return new this(r1, r2 ?? r1) + } + else { + throw TypeError("Invalid arguments") + } + } + + toString() { + const position = this.position? `at ${this.position}`: undefined + return cssFunc("circle", [this.r1, this.r2, position]) + } +} + +export class CSSRectValue implements CSSStyleValue { + constructor( + readonly shape: {top: CSSLengthValue | CSSPercentageValue, right: CSSLengthValue | CSSPercentageValue, bottom: CSSLengthValue | CSSPercentageValue, left: CSSLengthValue | CSSPercentageValue} | {x: CSSLengthValue | CSSPercentageValue, y: CSSLengthValue | CSSPercentageValue, w: CSSLengthValue | CSSPercentageValue, h: CSSLengthValue | CSSPercentageValue}, + readonly borderRadiusTopLeftR1?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusTopLeftR2?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusTopRightR1?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusTopRightR2?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusBottomRightR1?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusBottomRightR2?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusBottomLeftR1?: CSSLengthValue | CSSPercentageValue, + readonly borderRadiusBottomLeftR2?: CSSLengthValue | CSSPercentageValue, + readonly inset = false + ) {} + + get borderRadiusString() { + const r1 = [this.borderRadiusTopLeftR1, this.borderRadiusTopRightR1, this.borderRadiusBottomRightR1, this.borderRadiusBottomLeftR1].filter(el => el) + const r2 = [this.borderRadiusTopLeftR2, this.borderRadiusTopRightR2, this.borderRadiusBottomRightR2, this.borderRadiusBottomLeftR2].filter(el => el) + return [...r1, ...r2].length + ? undefined + : `${r1.join(" ")}` + r2.length? "/ " + r2.join(" "): "" + } + + get shapeString() { + return "x" in this.shape + ? `${this.shape.x} ${this.shape.y} ${this.shape.w} ${this.shape.h}` + : `${this.shape.top} ${this.shape.right} ${this.shape.bottom} ${this.shape.left}` + } + + static parseBorderRadius(text: string) { + const [r1, r2] = text.split(/\s+\/\s+/) + const [a1, b1, c1, d1] = r1.split(/\s+/).map(r => r? parseLengthOrPercentage(r): undefined) + const [a2, b2, c2, d2] = r2.split(/\s+/).map(r => r? parseLengthOrPercentage(r): undefined) + return [ + a1, + a2, + b1 ?? a1, + b2 ?? a2, + c1 ?? a1, + c2 ?? a2, + d1 ?? b1 ?? a1, + d2 ?? b2 ?? a2, + ] + } + + static parseShape(text: string, type:"rect" | "inset" | "xywh") { + const [a, b, c, d] = text.split(/\s+/).map(r => r? parseLengthOrPercentage(r): undefined) + return type === "xywh" + ? {x: a!, y: b!, w: c!, h: d!} + : {top: a!, right: b ?? a!, bottom: c ?? a!, left: d ?? b ?? a!} + } + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(!["rect", "inset", "xywh"].includes(name)) throw TypeError("Invalid function name") + const shape = args.slice(0, args.indexOf("round")).join(" ") + const rs = args.slice(args.indexOf("round") + 1).join(" ") + const [a1, a2, b1, b2, c1, c2, d1, d2] = this.parseBorderRadius(rs) + return new this(this.parseShape(shape, name as "rect" | "inset" | "xywh"), a1, a2, b1, b2, c1, c2, d1, d2, name === "inset") + } + + toString() { + return cssFunc("x" in this.shape? "xywh": (this.inset? "inset": "rect"), [this.shapeString? this.shapeString: undefined, this.borderRadiusString? "round " + this.borderRadiusString: undefined]) + } +} + +export class CSSPolygonValue implements CSSStyleValue { + + constructor( + readonly vertices: [CSSLengthValue | CSSPercentageValue, CSSLengthValue | CSSPercentageValue][], + readonly rounding?: CSSLengthValue, + readonly fillRule?: "nonzero" | "evenodd" + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "polygon") throw TypeError("Invalid function name") + const prefix = ["nonzero", "evenodd", "round "].some(s => args[0].includes(s))? args[0]: undefined + let rounding, fillRule + if(prefix?.includes("round ")) { + const [_, r] = prefix.split("round ") + rounding = CSSLengthValue.parse(r) + } + if(prefix?.includes("nonzero")) { + fillRule = "nonzero" + } + else if(prefix?.includes("evenodd")) { + fillRule = "evenodd" + } + const vertices = args.slice(prefix? 1: 0).map(vstr => vstr.split(/\s+/)).map(([v1, v2]) => [parseLengthOrPercentage(v1), parseLengthOrPercentage(v2)] as const) + return new this(vertices as any, rounding, fillRule as any) + } + + toString() { + const prefix = this.fillRule? `${this.fillRule}` + (this.rounding? `round ${this.rounding}`: ""): "" + return cssFunc("polygon", [prefix, ...this.vertices.map(([x, y]) => `${x} ${y}`)], ", ") + } +} + +export class CSSPathValue implements CSSStyleValue { + + constructor(readonly path: string, readonly fillRule?: "nonzero" | "evenodd") {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "path") throw TypeError("Invalid function name") + let fillRule: "nonzero" | "evenodd" | undefined + if(args[0]?.includes("nonzero")) { + fillRule = "nonzero" + } + else if(args[0]?.includes("evenodd")) { + fillRule = "evenodd" + } + const path = args[fillRule? 1: 0].slice(1, -1) + return new this(path, fillRule) + } + + toString() { + return cssFunc("path", [this.fillRule, `"${this.path}"`], ", ") + } +} + +export class CSSAttrValue implements CSSStyleValue { + constructor( + readonly name: string, + readonly type?: "string" | "ident" | "color" | "number" | "percentage" | "length" | "angle" | "time" | "frequency" | "url" | "flex" | "em" | "ex" | "px" | "rem" | "vw" | "vh" | "vmin" | "vmax" | "mm" | "cm" | "in" | "pt" | "pc" | "deg" | "grad" | "rad" | "time" | "s" | "ms" | "Hz" | "kHz" | "%", + readonly fallback?: CSSStyleValue + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "attr") throw TypeError("Invalid function name") + const [attrName, type] = args[0].split(/\s+/) + const fallback = args[1]? [...CSSCompositeValue.parse(args[1])][0]: undefined + return new this(attrName!, type as CSSAttrValue["type"], fallback) + } + + toString() { + const namePart = [this.name, ...(this.type ? [this.type]: [])].map(v => v.toString()).join(" ") + return cssFunc("attr", [namePart, this.fallback], ", ") + } +} + +export class CSSEnvValue implements CSSStyleValue { + constructor( + readonly name: string, + readonly dimensions?: CSSIntegerValue[], + readonly fallback?: CSSStyleValue + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "attr") throw TypeError("Invalid function name") + const [varName, ...dimensionParts] = args[0].split(/\s+/) + const dimensions = dimensionParts.map(part => CSSIntegerValue.parse(part)) + const fallback = args[1]? [...CSSCompositeValue.parse(args[1])][0]: undefined + return new this(varName!, dimensions, fallback) + } + + toString() { + const namePart = [this.name, ...(this.dimensions ?? [])].map(v => v.toString()).join(" ") + return cssFunc("env", [namePart, this.fallback], ", ") + } +} + +export class CSSUrlValue implements CSSStyleValue { + constructor( + readonly value: string, + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "url") throw TypeError("Invalid function name") + return new this(args[0].slice(args[0].startsWith('"')? 1: 0, args[0].endsWith('"')? -1: undefined)) + } + + toString() { + return cssFunc("url", [this.value]) + } +} + +export class CSSVarValue implements CSSStyleValue { + constructor( + readonly value: string, + readonly fallback?: CSSStyleValue + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "var") throw TypeError("Invalid function name") + const attrName = args[0] + const fallback = args[1]? [...CSSCompositeValue.parse(args[1])][0]: undefined + return new this(attrName, fallback) + } + + toString() { + return cssFunc("var", [this.value, this.fallback], ", ") + } +} + +export class CSSFitContentValue implements CSSStyleValue { + constructor(readonly value: CSSLengthValue | CSSPercentageValue) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "fit-content") throw TypeError("Invalid function name") + return new this(parseLengthOrPercentage(args.join(" "))) + } + + toString() { + return cssFunc("fit-content", [this.value]) + } +} + +export class CSSMinMaxValue implements CSSStyleValue { + constructor( + readonly min: CSSLengthValue | CSSPercentageValue | CSSFlexValue | "min-content" | "max-content" | "auto", + readonly max: CSSLengthValue | CSSPercentageValue | CSSFlexValue | "min-content" | "max-content" | "auto", + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "minmax") throw TypeError("Invalid function name") + const [min, max] = args.map(arg => { + if(["min-content", "max-content", "auto"].includes(arg)) { + return arg as "min-content" | "max-content" | "auto" + } + else if(arg.endsWith("fr")) { + return CSSFlexValue.parse(arg) + } + else { + return parseLengthOrPercentage(arg) + } + }) + return new this(min, max) + } + + toString() { + return cssFunc("minmax", [this.min, this.max], ", ") + } +} + +export class CSSRepeatValue implements CSSStyleValue { + constructor( + readonly count: CSSIntegerValue | "auto-fill" | "auto-fit", + readonly tracks: { + names?: string[], + size: CSSLengthValue | CSSPercentageValue | CSSFlexValue | CSSMinMaxValue | CSSFitContentValue | "min-content" | "max-content" + }[] + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "repeat") throw TypeError("Invalid function name") + const count = ["auto-fill", "auto-fit"].includes(args[0])? args[0] as "auto-fill" | "auto-fit": CSSIntegerValue.parse(args[0]) + const tracks: CSSRepeatValue["tracks"] = [] + for(const token of args[1].split(/\s+/)) { + if(token.startsWith("[") && tracks.length) { + tracks.at(-1)!.names = token.slice(1, -1).split(/\s+/) + } + else { + let size: CSSRepeatValue["tracks"][number]["size"] + if(["min-content", "max-content"].includes(token)) { + size = token as "min-content" | "max-content" + } + else if(token.endsWith("fr")) { + size = CSSFlexValue.parse(token) + } + else if(token.startsWith("min-max(")) { + size = CSSMinMaxValue.parse(token) + } + else if(token.startsWith("fit-content(")) { + size = CSSFitContentValue.parse(token) + } + else { + size = parseLengthOrPercentage(token) + } + tracks.push({size}) + } + } + return new this(count, tracks) + } + + toString() { + const tracks = this.tracks.map(track => `${track.size}` + (track.names?.length? ` [${track.names.join(" ")}]`: "")).join(" ") + return cssFunc("repeat", [this.count, tracks], ", ") + } +} + +export class CSSLinearValue implements CSSStyleValue { + constructor( + readonly stops: {point: CSSNumberValue, start?: CSSPercentageValue, end?: CSSPercentageValue}[] + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "linear") throw TypeError("Invalid function name") + const stops = args.map(arg => { + const parts = arg.split(/\s+/) + let point = CSSNumberValue.parse(parts.find(part => !part.endsWith("%"))!) + let start = CSSPercentageValue.parse(parts.find(part => part.endsWith("%"))!) + let end = CSSPercentageValue.parse(parts.reverse().find(part => part.endsWith("%"))!) + return {point, start, end} + }) + return new this(stops) + } + + toString() { + return cssFunc("linear", this.stops.map(stop => `${stop.point} ${stop.start} ${stop.end}`), ", ") + } +} + +export class CSSCubicBezierValue implements CSSStyleValue { + constructor( + readonly x1: CSSNumberValue, + readonly y1: CSSNumberValue, + readonly x2: CSSNumberValue, + readonly y2: CSSNumberValue + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "cubic-bezier") throw TypeError("Invalid function name") + const [x1, y1, x2, y2] = args.map(a => CSSNumberValue.parse(a)) + return new this(x1, y1, x2, y2) + } + + toString() { + return cssFunc("cubic-bezier", [this.x1, this.y1, this.x2, this.y2], ", ") + } +} + +export class CSSStepsValue implements CSSStyleValue { + constructor( + readonly amount: CSSNumberValue, + readonly stepPosition?: "jump-start" | "start" | "jump-end" | "end" | "jump-none" | "jump-both" + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "steps") throw TypeError("Invalid function name") + const amount = CSSNumberValue.parse(args[0]) + let stepPosition + if(args[1]) { + stepPosition = args[1] as CSSStepsValue["stepPosition"] + } + return new this(amount, stepPosition) + } + + toString() { + return cssFunc("steps", [this.amount, this.stepPosition], ", ") + } +} + +export class CSSElementValue implements CSSStyleValue { + constructor(readonly id: string) {} + + static parse(text: string): CSSElementValue { + const {name, args} = parseCssFunc(text, ",") + if(name !== "element") throw TypeError("Invalid function name") + return new this(args.join("")) + } + + toString() { + return cssFunc("element", [this.id]) + } +} + +export class CSSImageSetValue implements CSSStyleValue { + constructor( + readonly values: {image: CSSImageValue, resolution?: CSSResolutionValue, type?: MediaType}[] + ) {} + + static parse(text: string): CSSImageSetValue { + const {name, args} = parseCssFunc(text, ",") + if(name !== "image-set") throw TypeError("Invalid function name") + const values = args.map(arg => { + const parts = arg.split(/\s+/) + const image = CSSImageValue.parse(parts[0]) + const resolutionPart = parts.find(part => !part.startsWith("type(")) + const resolution = resolutionPart? CSSResolutionValue.parse(resolutionPart): undefined + const typePart = parts.find(part => !part.startsWith("type("))?.slice('type("'.length, '")'.length) + const type = typePart? new MediaType(typePart): undefined + return {image, resolution, type} + }) + return new this(values) + } + + toString() { + const values = this.values.map(v => { + const parts = [v.image, v.resolution, v.type].filter(p => p) + return parts.join(" ") + }) + return cssFunc("image-set", values, ", ") + } +} + +export class CSSCrossFadeValue implements CSSStyleValue { + constructor( + readonly stops: {value: CSSColorValue | CSSImageValue, opacity?: CSSPercentageValue}[] + ) {} + + static parse(text: string): CSSCrossFadeValue { + const {name, args} = parseCssFunc(text, ",") + if(name !== "cross-fade") throw TypeError("Invalid function name") + const stops = args.map(arg => { + const [valuePart, opacityPart] = arg.split(/\s+/) + let value + try { + value = CSSColorValue.parse(valuePart) + } + catch { + value = CSSImageValue.parse(valuePart) + } + let opacity + if(opacityPart) { + opacity = CSSPercentageValue.parse(opacityPart) + } + return {value, opacity} + }) + return new this(stops) + } + + toString() { + return cssFunc("cross-fade", this.stops.map(stop => `${stop.value}${stop.opacity? " " + stop.opacity: ""}`), ", ") + } +} + +export class CSSPaintValue implements CSSStyleValue { + constructor( + readonly name: string, + readonly values: CSSStyleValue[] = [] + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "paint") throw TypeError("Invalid function name") + const paintName = args[1] + const values = args.slice(1).map(arg => [...CSSCompositeValue.parse(arg)][0]) + return new this(paintName, values) + } + + toString() { + return cssFunc("paint", [this.name, ...this.values], ", ") + } +} + +export class CSSLeaderValue implements CSSStyleValue { + constructor( + readonly type: "dotted" | "solid" | "space" | CSSStringValue + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "leader") throw TypeError("Invalid function name") + const type = args[1] + return new this(type as any) + } + + toString() { + return cssFunc("leader", [this.type]) + } +} + +export class CSSAddValue implements CSSStyleValue { + constructor( + readonly depth: CSSIntegerValue + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "add") throw TypeError("Invalid function name") + const depth = CSSIntegerValue.parse(args[1]) + return new this(depth) + } + + toString() { + return cssFunc("add", [this.depth]) + } +} + +export class CSSAnchorSizeValue implements CSSStyleValue { + constructor( + readonly name?: string, + readonly size?: "width" | "height" | "block" | "inline" | "self-block" | "self-inline", + readonly fallback?: CSSLengthValue | CSSPercentageValue, + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "anchor-size") throw TypeError("Invalid function name") + const [anchorName, size] = args[0].split(/\w+/) + let fallback + if(args[1]) { + fallback = parseLengthOrPercentage(args[1]) + } + return new this(anchorName, size as any, fallback) + } + + toString() { + const prefix = [this.name, this.size].filter(v => v).join(" ") + return cssFunc("anchor-size", [prefix, this.fallback], ", ") + } +} + +export class CSSAlternativeGlyphValue implements CSSStyleValue { + constructor( + readonly type: "stylistic" | "styleset" | "character-variant" | "swash" | "ornament" | "annotation", + readonly names: string[] + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(!["stylistic", "styleset", "character-variant", "swash", "ornament", "annotation"].includes(name)) throw TypeError("Invalid function name") + return new this(name as any, args) + } + + toString() { + return cssFunc(this.type, this.names, ", ") + } +} + +export class CSSViewValue implements CSSStyleValue { + constructor( + readonly axis?: "block" | "inline" | "x" | "y", + readonly insets?: ["auto" | CSSLengthValue | CSSPercentageValue, "auto" | CSSLengthValue | CSSPercentageValue | undefined][] + ) {} + + static parse(text: string) { + let {name, args} = parseCssFunc(text, ",") + if(name !== "view") throw TypeError("Invalid function name") + let axis + if(args[0].startsWith("block") || args[0].startsWith("inline") || args[0].startsWith("x") || args[0].startsWith("y")) { + axis = args[0].split(/\s+/)[0] + args = [args[0].split(/\s+/).slice(1).join(), ...args] + } + else if(args.at(-1)!.endsWith("block") || args.at(-1)!.endsWith("inline") || args.at(-1)!.endsWith("x") || args.at(-1)!.endsWith("y")) { + axis = args.at(-1)!.split(/\s+/).at(-1)! + args = [args.at(-1)!.split(/\s+/).slice(0, -1).join(), ...args] + } + const insets = args.map(arg => arg.split(/\s+/).map(v => v && (v === "auto"? "auto": parseLengthOrPercentage(v)))) + return new this(axis as any, insets as any) + } + + toString() { + const insets = this.insets?.map(([a, b]) => `${a}${b? " "+b: ""}`).join(", ") + return cssFunc("view", [this.axis, insets]) + } +} + +export class CSSScrollValue implements CSSStyleValue { + constructor( + readonly scroller: "root" | "nearest" | "self", + readonly axis: "block" | "inline" | "x" | "y" + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text) + if(name !== "scroll") throw TypeError("Invalid function name") + const scroller = args.find(arg => ["root", "nearest", "self"].includes(arg)) + const axis = args.find(arg => ["block", "inline", "x", "y"].includes(arg)) + return new this(scroller as any, axis as any) + } + + toString() { + return cssFunc("scroll", [this.scroller, this.axis]) + } +} + +export class CSSTargetCounterValue implements CSSStyleValue { + constructor( + readonly type: "target-counter" | "target-counters", + readonly url: CSSUrlValue, + readonly name: string, + readonly separator?: string, + readonly counterStyle?: CSSCounterValue["style"] + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "target-counter" && name !== "target-counters") throw TypeError("Invalid function name") + const url = CSSUrlValue.parse(args[0]) + const counterName = args[1] + let separator, counterStyle + if(name === "target-counters") { + separator = args[2] + if(args[3]) { + counterStyle = CSSCounterValue.parseCounterStyle(args[3]) + } + } + else if(name === "target-counter" && args[2]) { + counterStyle = CSSCounterValue.parseCounterStyle(args[2]) + } + return name === "target-counter" + ? new this(name, url, counterName, undefined, counterStyle) + : new this(name, url, counterName, separator, counterStyle) + } + + toString() { + return cssFunc(this.type, [this.url, this.name, this.counterStyle], ", ") + } +} + +export class CSSTargetTextValue implements CSSStyleValue { + constructor( + readonly url: CSSUrlValue, + readonly retrieve?: "content" | "before" | "after" | "first-letter" + ) {} + + static parse(text: string) { + const {name, args} = parseCssFunc(text, ",") + if(name !== "target-text") throw TypeError("Invalid function name") + const url = CSSUrlValue.parse(args[0]) + return new this(url, args[1] as any) + } + + toString() { + return cssFunc("target-text", [this.url, this.retrieve], ", ") + } +} + +// COMPOSITE TYPES //////////////////////////////////////////////////////////// + +export class CSSCompositeValue implements CSSStyleValue { + + #values = [] as CSSStyleValue[] + + constructor(values: CSSStyleValue[]) { + this.#values = values + } + + // CSSTransformValue + static transformFunctionNames = ["translate", "translateX", "translateY", "translateZ", "translate3d", "rotate", "rotateX", "rotateY", "rotateZ", "rotate3d", "scale", "scaleX", "scaleY", "scaleZ", "scale3d", "skew", "skewX", "skewY", "matrix", "matrix3d", "perspective"] as const + + // CSSMathValue, TODO: CSSCalcSizeValue, CSSAnchorValue, CSSAnchorSizeValue + static mathFunctionNames = ["calc", "min", "max", "clamp", "round", "mod", "rem", "sin", "cos", "tan", "asin", "acos", "atan", "atan2", "pow", "sqrt", "hypot", "log", "exp", "abs", "sign", "calc-size", "anchor", "anchor-size"] as const + + // TODO: CSSBlurValue, CSSBrightnessValue, CSSContrastValue, CSSDropShadowValue, CSSGrayscaleValue, CSSHueRotateValue, CSSInvertValue, CSSOpacityValue, CSSSaturateValue, CSSSepiaValue + static filterFunctionNames = ["blur", "brightness", "contrast", "drop-shadow", "grayscale", "hue-rotate", "invert", "opacity", "saturate", "sepia"] as const + + // CSSColorValue, TODO: CSSColorMixValue, CSSColorContrastValue, CSSDeviceCmykValue, CSSLightDarkValue + static colorFunctionNames = ["rgb", "rgba", "hsl", "hsla", "hwb", "lch", "oklch", "oklab", "color", "color-mix", "color-contrast", "device-cmyk", "light-dark"] as const + + // CSSImageValue, TODO: CSSLinearGradientValue, CSSRadialGradientValue, CSSConicGradientValue, CSSCrossFadeValue, CSSElementValue, CSSPaintValue + static imageFunctionNames = ["linear-gradient", "radial-gradient", "conic-gradient", "repeating-linear-gradient", "repeating-radial-gradient", "repeating-conic-gradient", "image", "image-set", "cross-fade", "element", "paint"] as const + + // CSSCountersValue, CSSSymbolsValue + static counterFunctionNames = ["counter", "counters", "symbols"] as const + + // TODO: CSSShapeValue, CSSCircleValue, CSSEllipseValue, CSSInsetValue, CSSRectValue, CSSXywhValue, CSSPolygonValue, CSSPathValue + static shapeFunctionNames = ["shape", "circle", "ellipse", "inset", "rect", "xywh", "polygon", "path"] as const + + // TODO: CSSAttrValue, CSSEnvValue, CSSUrlValue, CSSVarValue + static referenceFunctionNames = ["attr", "env", "url", "var"] as const + + // TODO: CSSFitContentValue, CSSMinMaxValue, CSSRepeatValue + static gridFunctionNames = ["fit-content", "minmax", "repeat"] as const + + // TODO: CSSLinearValue, CSSCubicBezierValue, CSSStepsValue + static easingFunctionNames = ["linear", "cubic-bezier", "steps"] as const + + // TODO: CSSScrollValue, CSSViewValue + static animationFunctionNames = ["scroll", "view"] as const + + static functionNames = [...this.transformFunctionNames, ...this.mathFunctionNames, ...this.filterFunctionNames, ...this.colorFunctionNames, ...this.imageFunctionNames, ...this.counterFunctionNames, ...this.shapeFunctionNames, ...this.referenceFunctionNames, ...this.gridFunctionNames, ...this.easingFunctionNames, ...this.animationFunctionNames] + + static valueClasses = { + "color": CSSColorValue, + "hex-color": CSSColorValue, + "named-color": CSSColorValue, + "system-color": CSSColorValue, + "deprecated-system-color": CSSColorValue, + "declaration-value": CSSCompositeValue, + + "custom-ident": CSSCustomIdentValue, + "dashed-ident": CSSDashedIdentValue, + "string": CSSStringValue, + "integer": CSSIntegerValue, + "number": CSSNumberValue, + "percentage": CSSPercentageValue, + "flex": CSSFlexValue, + "ratio": CSSRatioValue, + "length": CSSLengthValue, + "angle": CSSAngleValue, + "time": CSSTimeValue, + "frequency": CSSFrequencyValue, + "resolution": CSSResolutionValue, + "position": CSSPositionValue, + "image": CSSImageValue, + "element": CSSImageValue, + + "translate": CSSTransformValue, + "translateX": CSSTransformValue, + "translateY": CSSTransformValue, + "translateZ": CSSTransformValue, + "translate3d": CSSTransformValue, + "rotate": CSSTransformValue, + "rotateX": CSSTransformValue, + "rotateY": CSSTransformValue, + "rotateZ": CSSTransformValue, + "rotate3d": CSSTransformValue, + "scale": CSSTransformValue, + "scaleX": CSSTransformValue, + "scaleY": CSSTransformValue, + "scaleZ": CSSTransformValue, + "scale3d": CSSTransformValue, + "skew": CSSTransformValue, + "skewX": CSSTransformValue, + "skewY": CSSTransformValue, + "matrix": CSSTransformValue, + "matrix3d": CSSTransformValue, + "perspective": CSSTransformValue, + + "calc": CSSMathValue, + "min": CSSMathValue, + "max": CSSMathValue, + "clamp": CSSMathValue, + "round": CSSMathValue, + "mod": CSSMathValue, + "rem": CSSMathValue, + "sin": CSSMathValue, + "cos": CSSMathValue, + "tan": CSSMathValue, + "asin": CSSMathValue, + "acos": CSSMathValue, + "atan": CSSMathValue, + "atan2": CSSMathValue, + "pow": CSSMathValue, + "sqrt": CSSMathValue, + "hypot": CSSMathValue, + "log": CSSMathValue, + "exp": CSSMathValue, + "abs": CSSMathValue, + "sign": CSSMathValue, + "anchor-size": CSSAnchorSizeValue, + "add": CSSAddValue, + /* Experimental + "calc-size": CSSMathValue, + "anchor": CSSMathValue*/ + + "rgb": CSSColorValue, + "rgba": CSSColorValue, + "hsl": CSSColorValue, + "hsla": CSSColorValue, + "hwb": CSSColorValue, + "lab": CSSColorValue, + "lch": CSSColorValue, + "oklch": CSSColorValue, + "oklab": CSSColorValue, + "color-mix": CSSColorMixValue, + "device-cmyk": CSSDeviceCmykValue, + "light-dark": CSSLightDarkValue, + + "blur": CSSBlurValue, + "brightness": CSSBrightnessValue, + "contrast": CSSContrastValue, + "drop-shadow": CSSDropShadowValue, + "grayscale": CSSGrayscaleValue, + "hue-rotate": CSSHueRotateValue, + "invert": CSSInvertValue, + "opacity": CSSOpacityValue, + "saturate": CSSSaturateValue, + "sepia": CSSSepiaValue, + + "linear-gradient": CSSLinearGradientValue, + "radial-gradient": CSSRadialGradientValue, + "conic-gradient": CSSConicGradientValue, + "repeating-linear-gradient": CSSLinearGradientValue, + "repeating-radial-gradient": CSSRadialGradientValue, + "repeating-conic-gradient": CSSConicGradientValue, + "image-set": CSSImageSetValue, + "cross-fade": CSSCrossFadeValue, + "paint": CSSPaintValue,/* Experimental + "image": CSSImageValue, + "element": CSSImageValue,*/ + + "counter": CSSCounterValue, + "counters": CSSCounterValue, + "symbols": CSSSymbolsValue, + + /* Experimental + "shape": CSSShapeValue,*/ + "circle": CSSCircleValue, + "ellipse": CSSEllipseValue, + "inset": CSSRectValue, + "rect": CSSRectValue, + "xywh": CSSRectValue, + "polygon": CSSPolygonValue, + "path": CSSPathValue, + + "attr": CSSAttrValue, + "env": CSSEnvValue, + "url": CSSUrlValue, + "var": CSSVarValue, + + "fit-content": CSSFitContentValue, + "minmax": CSSMinMaxValue, + "repeat": CSSRepeatValue, + + "linear": CSSLinearValue, + "cubic-bezier": CSSCubicBezierValue, + "steps": CSSStepsValue, + + "leader": CSSLeaderValue, + + "stylistic": CSSAlternativeGlyphValue, + "styleset": CSSAlternativeGlyphValue, + "character-variant": CSSAlternativeGlyphValue, + "swash": CSSAlternativeGlyphValue, + "ornament": CSSAlternativeGlyphValue, + "annotation": CSSAlternativeGlyphValue, + + "target-counter": CSSTargetCounterValue, + "target-counters": CSSTargetCounterValue, + "target-text": CSSTargetTextValue, + + "view": CSSViewValue, + "scroll": CSSScrollValue,/* Experimental + "palette-mix": CSSPaletteMixValue*/ + } + + static parse(cssText: string) { + const values = [] as CSSStyleValue[] + const tree = parser.parse(cssText) + treeLog(tree, cssText) + tree.iterate({ + enter: node => { + let str = cssText.slice(node.from, node.to) + let value: CSSStyleValue | undefined = undefined + if(["Dimension", "Number", "Percentage"].includes(node.name)) { + value = CSSNumericValue.parse(str) + } + else if(["Ident", "Initial", "Inherit", "Revert", "Unset"].includes(node.name)) { + value = new CSSKeywordValue(str) + } + else if(node.name === "String") { + value = new CSSStringValue(str) + } + else if(node.name === "DashedIdent") { + value = new CSSVariableReferenceValue(str) + } + else if(node.name === "Color") { + value = CSSColorValue.parse(str) + } + else if(node.name === "FunctionCall") { + const funcNameNode = node.node.firstChild! + const funcName: keyof (typeof CSSCompositeValue)["valueClasses"] = str.slice(funcNameNode.from, funcNameNode.to) as any + if(!this.functionNames.includes(funcName as any)) { + throw Error(`Unknown CSS function '${funcName}'`) + } + else { + values.push(this.valueClasses[funcName].parse(str)) + return false + } + } + value && values.push(value) + } + }) + return new CSSCompositeValue(values) + } + *[Symbol.iterator]() { + for(const value of this.#values) { + yield value + } + } +} + +// @ts-ignore +window.CSSCompositeValue = CSSCompositeValue + + +let errorCount = 0 +for(const [name, value] of Object.entries(CSSValueDefinition.CSSPropertySpecs)) { + try { + CSSValueDefinition.getSuggestions(value.syntaxTree!) + } catch(err) { + errorCount++ + console.error(name, value.syntaxTree, err) + } +} +errorCount && console.error(`${errorCount} ERRORS`) diff --git a/@webwriter/core/model/schemas/resourceschema/cssspec.ts b/@webwriter/core/model/schemas/cssvaluedefinition.data.ts similarity index 88% rename from @webwriter/core/model/schemas/resourceschema/cssspec.ts rename to @webwriter/core/model/schemas/cssvaluedefinition.data.ts index 852a8ac4..c3bd2696 100644 --- a/@webwriter/core/model/schemas/resourceschema/cssspec.ts +++ b/@webwriter/core/model/schemas/cssvaluedefinition.data.ts @@ -1,17 +1,13 @@ import rawProperties from "mdn-data/css/properties.json" import rawSyntaxes from "mdn-data/css/syntaxes.json" -import { filterObject } from "../../../utility" +import { filterObject } from "../utility" type KeysMatching = { [K in keyof T]-?: T[K] extends V ? K : never }[keyof T]; export const CSSPropertySpecs = { // TODO: Incorrectly typed until TS supports "import .json as const" - ...filterObject(rawProperties, (k, v) => ["standard", "experimental"].includes(v.status) || k === "font-smooth" || k === "zoom"), - "overflow-clip-margin": { // fix syntax error in base data - ...rawProperties["overflow-clip-margin"], - syntax: " || " - }, + ...filterObject(rawProperties, (k, v) => (["standard"].includes(v.status) || k === "font-smooth") && !["font-palette"].includes(k)), "animation-name": { ...rawProperties["animation-name"], forbiddenIdents: ["unset", "initial", "inherit", "none"] @@ -27,35 +23,48 @@ export const CSSPropertySpecs = { // TODO: Incorrectly typed until TS supports " "list-style-type": { ...rawProperties["list-style-type"], forbiddenIdents: ["unset", "initial", "inherit", "none", "inline", "outside", "disc", "circle", "square", "decimal", "cjk-decimal", "decimal-leading-zero", "lower-roman", "upper-roman", "lower-greek", "lower-alpha", "lower-latin", "upper-alpha", "upper-latin", "arabic-indic", "armenian", "bengali", "cambodian", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", "devanagari", "ethiopic-numeric", "georgian", "gujarati", "gurmukhi", "hebrew", "hiragana", "hiragana-iroha", "japanese-formal", "japanese-informal", "kannada", "katakana", "katakana-iroha", "khmer", "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", "lao", "lower-armenian", "malayalam", "mongolian", "myanmar", "oriya", "persian", "simp-chinese-formal", "simp-chinese-informal", "tamil", "telugu", "thai", "tibetan", "trad-chinese-formal", "trad-chinese-informal", "upper-armenian", "disclosure-open", "disclosure-closed"], - "grid-row-start": { - ...rawProperties["grid-row-start"], - forbiddenIdents: ["span"] - }, - "grid-row-end": { - ...rawProperties["grid-row-end"], - forbiddenIdents: ["span"] - }, - "grid-column-start": { - ...rawProperties["grid-column-start"], - forbiddenIdents: ["span"] - }, - "grid-column-end": { - ...rawProperties["grid-column-end"], - forbiddenIdents: ["span"] - }, - "view-transition-name": { - ...rawProperties["view-transition-name"], - forbiddenIdents: ["unset", "initial", "inherit", "none"] - }, - "will-change": { - ...rawProperties["will-change"], - forbiddenIdents: ["unset", "initial", "inherit", "will-change", "auto", "scroll-position", "contents"] - }, }, + "grid-row-start": { + ...rawProperties["grid-row-start"], + forbiddenIdents: ["span"] + }, + "grid-row-end": { + ...rawProperties["grid-row-end"], + forbiddenIdents: ["span"] + }, + "grid-column-start": { + ...rawProperties["grid-column-start"], + forbiddenIdents: ["span"] + }, + "grid-column-end": { + ...rawProperties["grid-column-end"], + forbiddenIdents: ["span"] + }, + "view-transition-name": { + ...rawProperties["view-transition-name"], + forbiddenIdents: ["unset", "initial", "inherit", "none"] + }, + "will-change": { + ...rawProperties["will-change"], + forbiddenIdents: ["unset", "initial", "inherit", "will-change", "auto", "scroll-position", "contents"] + }, + "offset-path": { + ...rawProperties["offset-path"], + syntax: "none | | || " // | ray + } } as unknown as Omit +// Sequencing hotfix +const syntaxesSequence = ["length-percentage", "visual-box", "box", "line-names", "name-repeat", "masking-mode", "mask-source", "target", "cubic-bezier-timing-function", "step-timing-function", "single-animation-iteration-count", "single-animation-direction", "single-animation-fill-mode", "single-animation-play-state", "bg-position", "transition-behavior-value", "single-animation-timeline", "single-transition-property", "easing-function", "shape-box", "quote", "display-outside", "counter-style-name", "mask-reference", "paint-box"] export type CSSSyntaxes = typeof rawSyntaxes -export const CSSSyntaxes = rawSyntaxes +export const CSSSyntaxes = { + ...Object.fromEntries(syntaxesSequence.map(k => [k, (rawSyntaxes as any)[k]])), + ...filterObject(rawSyntaxes, k => !syntaxesSequence.includes(k) && !(k === "offset-path")), + "keyframe-block": { + ...rawSyntaxes["keyframe-block"], + syntax: "# '{' '}'" + } +} export type CSSPropertySpecs = typeof CSSPropertySpecs diff --git a/@webwriter/core/model/schemas/valuedefinition/index.grammar b/@webwriter/core/model/schemas/cssvaluedefinition.grammar similarity index 68% rename from @webwriter/core/model/schemas/valuedefinition/index.grammar rename to @webwriter/core/model/schemas/cssvaluedefinition.grammar index c2803180..f64ccdd3 100644 --- a/@webwriter/core/model/schemas/valuedefinition/index.grammar +++ b/@webwriter/core/model/schemas/cssvaluedefinition.grammar @@ -1,11 +1,11 @@ -@top ValueDefinition { expression } +@top CSSValueDefinition { expression } expression { simpleExpression | complexExpression | groupExpression } simpleExpression { Literal | stringExpression | PropertyReference | DataType } -complexExpression { OrderedSequence | UnorderedSequence | Subset | Alternation } +complexExpression { OrderedSequence | UnorderedSequence | Subset | Alternation | FunctionCall } groupExpression { Group @@ -24,21 +24,28 @@ PropertyReference { } DataType { - "<" Identifier ">" quantifier? + "<" Identifier Range? ">" quantifier? } +FunctionCall { + Identifier "(" expression ")" +} -OrderedSequence { list } +OrderedSequence { list } -UnorderedSequence { list } +UnorderedSequence { list } -Subset { list } +Subset { list } -Alternation { list } +Alternation { list } list { expr (sep expr)+ } Group {"[" expr "]" (Required | quantifier)?} +Range { "[" Start { number | dimension | neginf } "," End { number | dimension | posinf } "]"} + +dimension { number unit } + quantifier[@isGroup=Quantifier] { ZeroOrMore | OneOrMore | ZeroOrOne | Some | OneOrMoreCommaSeparated } ZeroOrMore { "*" } @@ -51,11 +58,14 @@ OneOrMoreCommaSeparated { "#" (ZeroOrMore | OneOrMore | ZeroOrOne | Some)? } // or { "|" } // andor { "||" } - Identifier { $[a-zA-Z0-9_\-]+ } - literalString { "," | "." | "(" | ")" | "/" } + Identifier { $[a-zA-Z0-9_\-]+ "()"? } + literalString { "," | "." | "/" } whitespace { $[ \n\r\t]} Required { "!" } number { @digit+ } + neginf { "-∞" } + posinf { "∞" | "+∞" } + unit { $[a-zA-Z] $[a-zA-Z]* } } @local tokens { diff --git a/@webwriter/core/model/schemas/cssvaluedefinition.ts b/@webwriter/core/model/schemas/cssvaluedefinition.ts new file mode 100644 index 00000000..1adc7369 --- /dev/null +++ b/@webwriter/core/model/schemas/cssvaluedefinition.ts @@ -0,0 +1,373 @@ +import {parser} from "./cssvaluedefinition.grammar" +import { CSSPropertySpecs, CSSSyntaxes } from "./cssvaluedefinition.data" +import { CSSAngleValue, CSSColorValue, CSSCompositeValue, CSSCustomIdentValue, CSSDashedIdentValue, CSSFlexValue, CSSFrequencyValue, CSSIntegerValue, CSSLengthValue, CSSNumberValue, CSSPercentageValue, CSSPositionValue, CSSRatioValue, CSSResolutionValue, CSSStringValue, CSSTimeValue, CSSUrlValue } from "./cssvalue" +import { filterObject } from "../utility" + +export function treeLog(tree: any, expr?: string) { + let depth = -1 + tree.cursor().iterate( + (node: any) => { + depth++ + console.group(`${node.name}[${node.from}:${node.to}|${depth}]`, expr?.slice(node.from, node.to)) + }, + () => { + depth-- + console.groupEnd() + } + ) +} + +const errorEntries = Object.entries(CSSPropertySpecs) + .map(([name, spec]) => [name, spec, parser.parse(spec.syntax)] as const) + .filter(([name, spec, tree]) => { + let isError = false + tree.iterate({ + enter: (node: any) => {isError = node.type.isError} + }) + return isError + }) + +/* +errorEntries.forEach(([name, spec, tree]) => { + console.error(name, spec.syntax) + treeLog(tree) +}) +errorEntries.length && console.error(`${errorEntries.length} errors found`) + +console.log(errorEntries)*/ + +interface BaseExpression { + type: string + min: number + max: number + separator?: string + required?: boolean + raw: string + parent?: ICSSValueDefinition + name?: string +} + +interface Literal extends BaseExpression { + type: "Literal" + content: string + options?: string[] +} + +interface DataType extends BaseExpression { + type: "DataType" + content: string +} + +interface OrderedSequence extends BaseExpression { + type: "OrderedSequence" + content: ICSSValueDefinition[] +} + +interface UnorderedSequence extends BaseExpression { + type: "UnorderedSequence" + content: ICSSValueDefinition[] +} + +interface Subset extends BaseExpression { + type: "Subset" + content: ICSSValueDefinition[] +} + +interface Alternation extends BaseExpression { + type: "Alternation" + content: ICSSValueDefinition[] +} + +interface FunctionCall extends BaseExpression { + type: "FunctionCall" + name: string + content: ICSSValueDefinition[] +} + +type CSSValueSuggestion = CSSStyleValue | (typeof CSSStyleValue) + +export type ICSSValueDefinition = Literal | DataType | OrderedSequence | UnorderedSequence | Subset | Alternation | FunctionCall +export const CSSValueDefinition = class CSSValueDefinition { + + static parseQuantifier(node: any, str: string): {min: number, max?: number, separator?: string} { + if(node?.name === "ZeroOrMore") { + return {min: 0, max: Infinity} + } + else if(node?.name === "OneOrMore") { + return {min: 1, max: Infinity} + } + else if(node?.name === "ZeroOrOne") { + return {min: 0, max: 1} + } + else if(node?.name === "Some") { + const minNode = node.node.getChild("Min") + const min = parseInt(str.slice(minNode.from, minNode.to)) + const maxNode = node.node.getChild("Max") + const max = maxNode? parseInt(str.slice(maxNode.from, maxNode.to)): undefined + return {min, max} + } + else if (node?.name === "OneOrMoreCommaSeparated") { + return {min: 1, max: Infinity, separator: ",", ...(["ZeroOrMore", "OneOrMore", "ZeroOrOne", "Some"].includes(node.lastChild?.name)? this.parseQuantifier(node.lastChild!, str): undefined)} + } + else { + return {min: 1, max: 1} + } + } + + static parse(str: string, cache?: Record, name?: string) { + const tree = parser.parse(str) + // treeLog(tree, str) + let root = undefined as ICSSValueDefinition | undefined + let parent = undefined as ICSSValueDefinition["parent"] + let groupQuantification: undefined | {min: number, max: number, separator?: string, required?: boolean} + tree.iterate({ + enter: node => { + const raw = str.slice(node.from, node.to) + let expr: ICSSValueDefinition | null = null + if(["Literal", "String"].includes(node.name)) { + const qNode = node.node.getChild("Quantifier")! + const cNode = node.name !== "String"? node.node.getChild("Identifier")!: null + expr = {type: node.name, ...this.parseQuantifier(qNode, str), raw, content: node.name !== "String"? str.slice(cNode!.from, cNode!.to): raw} as any + if(parent && Array.isArray(parent.content)) { + parent.content.push(expr!) + } + if(!root) { + root = expr!; + (root as any).name = name + if(cache && name) { + cache[name] = Object.assign(cache[name] ?? {}, expr) + } + } + } + else if(["DataType", "PropertyReference"].includes(node.name)) { + const cNode = node.node.getChild("Identifier")! + const qNode = node.node.getChild("Quantifier")! + const id = str.slice(cNode.from, cNode.to) + if(cache && id in cache) { + expr = cache[id] + } + else if(node.name === "PropertyReference" && cache && !(id in cache)) { + expr = cache[id] = {} as any + } + else { + expr = {type: node.name, name: id, content: id, ...this.parseQuantifier(qNode, str), raw} as any + } + if(parent && Array.isArray(parent.content)) { + parent.content.push(expr!) + } + if(!root) { + root = expr!; + (root as any).name = name + if(cache && name && expr) { + cache[name] = Object.assign(cache[name] ?? {}, expr) + } + } + } + else if(["OrderedSequence", "UnorderedSequence", "Subset", "Alternation", "FunctionCall"].includes(node.name)) { + expr = {type: node.name, raw, content: [], min: 1, max : 1, ...groupQuantification} as any + groupQuantification = undefined + if(node.name === "FunctionCall") { + const nameNode = node.node.firstChild! + const name = str.slice(nameNode.from, nameNode.to); + (expr as any).name = name + } + if(parent && Array.isArray(parent.content)) { + parent.content.push(expr!) + } + parent = expr! + if(!root) { + root = expr!; + (root as any).name = name + if(cache && name) { + cache[name] = Object.assign(cache[name] ?? {}, expr) + } + } + } + else if(node.name === "Group") { + const qNode = node.node.getChild("Quantifier") + groupQuantification = this.parseQuantifier(qNode, str) as any + } + if(["String", "Literal", "DataType", "PropertyReference"].includes(node.name)) { + return false + } + } + }) + return root + } + + static styleValueFitsDefinition(def: ICSSValueDefinition, val: CSSStyleValue): boolean { + const isComplex = ["OrderedSequence", "UnorderedSequence", "Subset", "Alternation"].includes(def.type) + const fitsLiteral = def.type === "Literal" && (val instanceof CSSKeywordValue) && def.content === val.value + const fitsType = ["DataType", "FunctionCall"].includes(def.type) && (def.name ?? "") in CSSCompositeValue.valueClasses && val instanceof CSSCompositeValue.valueClasses[(def.name as keyof typeof CSSCompositeValue.valueClasses)] + return !isComplex && (fitsLiteral || fitsType) + } + + private static decrementValueDefinition(def: ICSSValueDefinition): ICSSValueDefinition | null { + let min = Math.max(0, def.min - 1) + let max = def.max - 1 + if(max <= 0) { + return null + } + else return {...def, min, max} + } + + static reduceValueDefinition(def: ICSSValueDefinition, value: CSSStyleValue): ICSSValueDefinition | null { + if(def.type === "OrderedSequence") { + const head: ICSSValueDefinition = { + type: "OrderedSequence", + raw: "", + min: 1, + max: 1, + content: [this.reduceValueDefinition(def.content[0], value), ...def.content.slice(1)].filter(v => v !== null) + } + const tail = this.decrementValueDefinition(def) + if(!head.content.length && !tail) { + return null + } + return tail? { + type: "OrderedSequence", + content: [...head.content, tail], + min: 1, + max: 1, + raw: "" + }: head + } + else if(def.type === "Alternation") { + for(const c of def.content as ICSSValueDefinition[]) { + const reduced = this.reduceValueDefinition(c, value) + if(reduced) { + return this.decrementValueDefinition({...def, content: [...def.content]}) + } + } + return null + } + else if(def.type === "UnorderedSequence") { // a && b + for(const [i, c] of (def.content as ICSSValueDefinition[]).entries()) { + const reduced = this.reduceValueDefinition(c, value) + if(reduced) { + const head: ICSSValueDefinition = { + type: "UnorderedSequence", + raw: "", + min: 1, + max: 1, + content: [ + ...def.content.slice(0, i), + reduced, + ...def.content.slice(i + 1) + ].filter(v => v !== null) + } + const tail = this.decrementValueDefinition(def) + if(!head.content.length && !tail) { + return null + } + return tail? { + type: "OrderedSequence", + content: [head, tail], + min: 1, + max: 1, + raw: "" + }: head + } + } + return null + } + else if(def.type === "Subset") { // a || b + for(const [i, c] of (def.content as ICSSValueDefinition[]).entries()) { + const reduced = this.reduceValueDefinition(c, value) + if(reduced) { + const head: ICSSValueDefinition = { + type: "Subset", + raw: "", + min: 1, + max: 1, + content: [ + ...def.content.slice(0, i), + reduced, + ...def.content.slice(i + 1) + ].filter(v => v !== null) + } + const tail = this.decrementValueDefinition(def) + if(!head.content.length && !tail) { + return null + } + return tail? { + type: "OrderedSequence", + content: [head, tail], + min: 1, + max: 1, + raw: "" + }: head + } + } + return null + } + else if(def.type === "FunctionCall" || def.type === "DataType") { + const applies = value instanceof (CSSCompositeValue.valueClasses as any)[def.name ?? ""] + return applies? this.decrementValueDefinition(def): null + } + else { // def.type === "Literal" + const applies = (def.content as string) === value.toString() + return applies? this.decrementValueDefinition(def): null + } + } + + static getSuggestions(def: ICSSValueDefinition): CSSValueSuggestion[] { + if(def.type === "Alternation" || def.type === "UnorderedSequence") { + return Array.from(new Set(def.content.flatMap(v => this.getSuggestions(v)))) + } + else if(def.type === "OrderedSequence") { + return Array.from(new Set(this.getSuggestions(def.content[0]))) + } + else if(def.type === "Subset") { + return Array.from(new Set(def.content.flatMap(v => this.getSuggestions(v)))) + } + else if(def.type === "DataType" || def.type === "FunctionCall") { + const name = def.type === "FunctionCall" + ? def.name?.replace("()", "") ?? "" + : def.content?.replace("()", "") ?? "" + const cls = (CSSCompositeValue.valueClasses as any)[name] as CSSStyleValue + if(!cls) { + throw TypeError(`Unknown data type '${name}' in expression '${def.raw}'`) + } + return [cls] + } + else { // def.type === "Literal" + return [new CSSKeywordValue(def.content)] + } + } + + /*static *suggestionsGenerator(def: ICSSValueDefinition): Generator { + let currentDef = def + while(currentDef) { + const value = yield this.getSuggestions(def) + currentDef = this.reduceValueDefinition(def, value) + } + }*/ + + static suggestionsAt(def: ICSSValueDefinition, val: CSSCompositeValue) { + const currentDef = Array.from(val) + .reduce((acc: ICSSValueDefinition, cur) => { + const reduced = this.reduceValueDefinition(acc, cur) + return reduced? reduced: acc + }, def) + return this.getSuggestions(currentDef) + } + + static parseCSSPropertySpecs(specs: CSSPropertySpecs, syntaxes?: CSSSyntaxes) { + const cache = {} + /*Object.keys(syntaxes ?? {}).forEach(k => { + (cache as any)[k] = this.parse((syntaxes as any)[k].syntax, cache, k) + })*/ + const all = Object.fromEntries(Object.entries({...syntaxes, ...specs}).map(([name, spec]) => { + return [ + name, + {...spec, syntaxTree: this.parse(spec.syntax, cache, name)} + ] + })) + return filterObject(all, k => Object.keys(specs).includes(k)) + } + static CSSPropertySpecs = this.parseCSSPropertySpecs(CSSPropertySpecs, CSSSyntaxes as any) +} + +// @ts-ignore +window.CSSValueDefinition = CSSValueDefinition \ No newline at end of file diff --git a/@webwriter/core/model/schemas/customelementsmanifest.test.ts b/@webwriter/core/model/schemas/customelementsmanifest.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/@webwriter/core/model/schemas/packageschema/customelementsmanifest.ts b/@webwriter/core/model/schemas/customelementsmanifest.ts similarity index 100% rename from @webwriter/core/model/schemas/packageschema/customelementsmanifest.ts rename to @webwriter/core/model/schemas/customelementsmanifest.ts diff --git a/@webwriter/core/model/schemas/datatypes.ts b/@webwriter/core/model/schemas/datatypes.ts deleted file mode 100644 index ce5e96ac..00000000 --- a/@webwriter/core/model/schemas/datatypes.ts +++ /dev/null @@ -1,292 +0,0 @@ -import {ZodSchema, z} from "zod" -import SPDX_LICENSE_MAP from "spdx-license-list" -import { - SemVer as NodeSemVer, - Range as NodeSemVerRange, - -} from "semver" -import ISO6391 from 'iso-639-1' -import { disjunctPipe, filterObject } from "../../utility" - -const SPDX_LICENSES = Object.keys(SPDX_LICENSE_MAP) -const MIME_NAME_ENCODING = { - "~": "_".repeat(16), - "|": "_".repeat(15), - "`": "_".repeat(14), - "^": "_".repeat(13), - "*": "_".repeat(12), - "'": "_".repeat(11), - "&": "_".repeat(10), - "%": "_".repeat(9), - "$": "_".repeat(8), - "#": "_".repeat(7), - "!": "_".repeat(6), - ";": "_".repeat(5), - "/": "_".repeat(4), - ".": "_".repeat(3), - "+": "_".repeat(2), - "-": "_".repeat(1), -} - - -const npmPersonPattern = /^\s*(?.*?)(?:<(?.+)>)?\s*(?:\((?.+)\))?\s*$/ -const mimePattern = /#?(?[\w!#$%&'*.^`|~-]+)(?:\/(?[\w!#$%&'*.^`|~-]+)(?:\+(?[\w!#$%&'*.^`|~-]+))?(?:;(?[\w!#$%&'*.^`|~-]+)=(?[\w!#$%&'*.^`|~-]+))?)?/ -const semverPattern = /(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[a-zA-Z\-][0-9a-zA-Z\-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z\-][0-9a-zA-Z\-]*))*))?(?:\+(?[0-9a-zA-Z\-]+(?:\.[0-9a-zA-Z\-]+)*))?/ -const npmNamePattern = /^(@(?[a-z0-9\-~][a-z0-9\-._~]*)\/)?(?[a-z0-9\-~][a-z0-9\-._~]*)$/ -const spdxLicensePattern = new RegExp(`^(${SPDX_LICENSES.map(x => x.replaceAll(".", "\.")).join("|")})$`) - -export interface Person extends z.infer {} -export class Person { - - static objectSchema = z.object({ - name: z.string().trim().optional(), - email: z.string().trim().optional(), - url: z.string().trim().optional() - }) - - static schema = z.string() - .regex(npmPersonPattern) - .transform(str => { - const groups = npmPersonPattern.exec(str)?.groups ?? {} - let {name, email, url} = groups - name = name?.trim() - email = email?.trim() - url = url?.trim() - const person = {...(name && {name}), ...(email && {email}), ...(url && {url})} as z.infer - return new Person(person) - }) - .or(Person.objectSchema.transform(x => new Person(x)) - - ) - - constructor(person: string | z.infer) { - return typeof person === "string" - ? Person.schema.parse(person) - : Object.assign(this, person) - } - - - toString() { - const name = this.name ?? "" - const email = this.email != null? ` <${this.email}>`: "" - const url = this.url != null? ` (${this.url})`: "" - return `${name}${email}${url}` - } - - toJSON() { - return this.toString() - } - - extend(extraProperties: Partial) { - return new Person({...this, ...extraProperties}) - } -} - -export class SemVer extends NodeSemVer { - - static pattern = semverPattern - - constructor(ver: string | SemVer | NodeSemVer, optionsOrLoose?: ConstructorParameters[1]) { - super(ver, optionsOrLoose) - } - - static schema = z.string().transform((x, ctx) => { - try { - return new this(x) - } - catch(err: any) { - ctx.addIssue({code: z.ZodIssueCode.custom, message: err.message}) - return z.NEVER - } - }).or(z.instanceof(this)) - - gt(other: string | SemVer | NodeSemVer) { - return this.compare(other) === 1 - } - - lt(other: string | SemVer | NodeSemVer) { - return this.compare(other) === -1 - } - - eq(other: string | SemVer | NodeSemVer) { - return this.compare(other) === 0 - } - - toString() { - const prerelease = this.prerelease.length? `-${this.prerelease.join(".")}`: "" - const build = this.build.length? `+${this.build.join(".")}`: "" - return `${this.major}.${this.minor}.${this.patch}${prerelease}${build}` - } - - toJSON = () => this.toString() -} - -export class SemVerRange extends NodeSemVerRange { - - constructor(range: string | SemVerRange | NodeSemVerRange, optionsOrLoose?: ConstructorParameters[1]) { - super(range, optionsOrLoose) - } - - static schema = z.string().transform((x, ctx) => { - try { - return new this(x) - } - catch(err: any) { - ctx.addIssue({code: z.ZodIssueCode.custom, message: err.message}) - return z.NEVER - } - }).or(z.instanceof(this)) - - toString = () => this.raw; toJSON = () => this.toString() -} - -export class License { - - static schema = z.string().transform(x => new this(x)).or(z.instanceof(this)) - - static spdxLicenseKeys = Object.keys(SPDX_LICENSE_MAP) - - key: string - - constructor(key: string | {key: string}) { - this.key = typeof key === "string"? key: key.key - } - - get name() { - return SPDX_LICENSE_MAP[this.key]?.name - } - - get url() { - return SPDX_LICENSE_MAP[this.key]?.url - } - - get osiApproved() { - return SPDX_LICENSE_MAP[this.key]?.osiApproved - } - - toString() { - return this.key - } - - toJSON() { - return this.toString() - } - -} - -export interface MediaType extends z.infer {} -export class MediaType { - - static objectSchema = disjunctPipe( - z.string().transform((arg, ctx) => { - if(!arg.startsWith("_") && !arg.startsWith("#")) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: `MediaType must start with '#' or '_'` - }) - return z.NEVER - } - const value = arg.startsWith("_") - ? Object.entries(MIME_NAME_ENCODING).reduce((acc, [k, v]) => acc.replaceAll(v, k), arg) - : arg - const match = value.match(mimePattern) - if(match) { - const {supertype, subtype, suffix, pkey, pvalue} = match.groups ?? {} - return {supertype, subtype, suffix, ...(pkey? {[pkey]: pvalue}: null)} - } - else { - return z.NEVER - } - }), - z.object({ - supertype: z.string(), - subtype: z.string(), - suffix: z.string().optional(), - pkey: z.string().optional(), - pvalue: z.string().optional() - }) - ) - - static schema = this.objectSchema.transform(x => Object.assign(Object.create(this.prototype), x)) - - constructor(mediaType: MediaType | z.input) { - return mediaType instanceof MediaType - ? mediaType - : MediaType.schema.parse(mediaType) - } - - toString(format: "expr" | "node" = "expr") { - if(format === "expr") { - const [paramKey, paramValue] = Object.entries(this).find(([k]) => k !== "supertype" && k !== "subtype" && k !== "suffix") ?? [] - const paramStr = paramKey? `;${paramKey}=${paramValue}`: "" - return `#${this?.supertype}/${this?.subtype}` + paramStr - } - else { - return `_${this?.supertype}____${this.subtype.replaceAll("-", "_")}` - } - } - - toJSON() { - return this.toString() - } -} - -export const bcp47Pattern = /^((?(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?([A-Za-z]{2,3}(-(?[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?