@mpeggroup/mpeg-sdl-editor 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.github/workflows/check-bun-dependencies.yml +13 -0
  2. package/.github/workflows/lint-pr-message.yml +13 -0
  3. package/.github/workflows/release-bun-webapp.yml +15 -0
  4. package/.github/workflows/validate-bun-webapp-pr.yml +9 -0
  5. package/LICENSE +21 -0
  6. package/README.md +59 -0
  7. package/build.ts +8 -0
  8. package/functional_tests/README.md +25 -0
  9. package/functional_tests/features/environment.py +50 -0
  10. package/functional_tests/features/steps/helper/selenium.py +15 -0
  11. package/functional_tests/features/steps/webapp.py +30 -0
  12. package/functional_tests/features/webapp.feature +5 -0
  13. package/functional_tests/pip-requirements.txt +2 -0
  14. package/html/favicon.svg +126 -0
  15. package/html/index.html +14 -0
  16. package/html/style.css +2 -0
  17. package/package.json +61 -0
  18. package/src/App.css +3 -0
  19. package/src/App.tsx +266 -0
  20. package/src/assets/mpeg.svg +143 -0
  21. package/src/codemirror/ruler.ts +58 -0
  22. package/src/components/DesktopPanels.tsx +65 -0
  23. package/src/components/Editor.tsx +384 -0
  24. package/src/components/MobileDrawer.tsx +57 -0
  25. package/src/components/Navbar.tsx +226 -0
  26. package/src/components/ResizableLayout.tsx +69 -0
  27. package/src/components/Settings.tsx +170 -0
  28. package/src/components/StatusBar.tsx +47 -0
  29. package/src/components/SubNav.tsx +58 -0
  30. package/src/hooks/useAutoDisplayCompletions.ts +26 -0
  31. package/src/hooks/useDragResize.ts +104 -0
  32. package/src/hooks/useEnableLinting.ts +21 -0
  33. package/src/hooks/useFileOperations.ts +102 -0
  34. package/src/hooks/useMobileDetection.ts +32 -0
  35. package/src/hooks/usePrettier.ts +40 -0
  36. package/src/hooks/useRulerWidth.ts +42 -0
  37. package/src/hooks/useShowSemanticWarnings.ts +23 -0
  38. package/src/hooks/useShowSymanticErrors.ts +23 -0
  39. package/src/hooks/useShowSyntaxErrors.ts +23 -0
  40. package/src/hooks/useTheme.ts +21 -0
  41. package/src/hooks/useToast.ts +37 -0
  42. package/src/logo/getLogoSvg.ts +5 -0
  43. package/src/logo/svg.module.d.ts +5 -0
  44. package/src/main.tsx +13 -0
  45. package/src/sdl/sdlComplete.ts +86 -0
  46. package/src/sdl/sdlLanguage.ts +18 -0
  47. package/src/sdl/sdlLinter.ts +157 -0
  48. package/tailwind.config.ts +16 -0
  49. package/tests/Editor_test.tsx +29 -0
  50. package/tests/happydom.ts +3 -0
  51. package/tests/sdlLanguage_test.ts +39 -0
  52. package/tsconfig.json +27 -0
@@ -0,0 +1,13 @@
1
+ name: check-bun-dependencies
2
+ on:
3
+ workflow_dispatch:
4
+ schedule:
5
+ - cron: "0 0 * * *"
6
+ permissions:
7
+ contents: read
8
+ pull-requests: write
9
+ jobs:
10
+ call-check-bun-dependencies:
11
+ uses: flowscripter/.github/.github/workflows/check-bun-dependencies.yml@v1
12
+ secrets:
13
+ CREATE_PR_TOKEN: ${{ secrets.CREATE_PR_TOKEN }}
@@ -0,0 +1,13 @@
1
+ name: lint-pr-message
2
+ on:
3
+ pull_request_target:
4
+ types:
5
+ - opened
6
+ - edited
7
+ - synchronize
8
+ permissions:
9
+ contents: read
10
+ jobs:
11
+ call-lint-pr-message:
12
+ uses: flowscripter/.github/.github/workflows/lint-pr-message.yml@v1
13
+ secrets: inherit
@@ -0,0 +1,15 @@
1
+ name: release-bun-webapp
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ permissions:
6
+ contents: write
7
+ issues: write
8
+ pull-requests: write
9
+ id-token: write
10
+ pages: write
11
+ jobs:
12
+ call-release-bun-webapp:
13
+ uses: flowscripter/.github/.github/workflows/release-bun-webapp.yml@v1
14
+ secrets:
15
+ PUSH_TO_MAIN_TOKEN: ${{ secrets.PUSH_TO_MAIN_TOKEN }}
@@ -0,0 +1,9 @@
1
+ name: validate-bun-webapp-pr
2
+ on:
3
+ pull_request:
4
+ branches: [main]
5
+ permissions:
6
+ contents: read
7
+ jobs:
8
+ call-validate-bun-webapp-pr:
9
+ uses: flowscripter/.github/.github/workflows/validate-bun-webapp-pr.yml@v1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Flowscripter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # mpeg-sdl-editor
2
+
3
+ [![version](https://img.shields.io/github/v/release/mpeggroup/mpeg-sdl-editor?sort=semver)](https://github.com/mpeggroup/mpeg-sdl-editor/releases)
4
+ [![build](https://img.shields.io/github/actions/workflow/status/mpeggroup/mpeg-sdl-editor/release-bun-webapp.yml)](https://github.com/mpeggroup/mpeg-sdl-editor/actions/workflows/release-bun-webapp.yml)
5
+ [![license: MIT](https://img.shields.io/github/license/mpeggroup/mpeg-sdl-editor)](https://github.com/mpeggroup/mpeg-sdl-editor/blob/main/LICENSE)
6
+
7
+ > ISO/IEC 14496-34 Syntactic Description Language (MPEG SDL) web based editor.
8
+
9
+ ## Hosted Instance
10
+
11
+ Go to: https://mpeggroup.github.io/mpeg-sdl-editor/
12
+
13
+ ## Parser Library
14
+
15
+ This editor makes use of: https://github.com/MPEGGroup/mpeg-sdl-parser
16
+
17
+ ## Development
18
+
19
+ `@mpeggroup/mpeg-sdl-parser` is hosted on GitHub packages, so before installing
20
+ dependencies, authentication needs to be configured. Create a GitHub classic
21
+ personal access token which has permission to read packages and then set it in
22
+ your environment:
23
+
24
+ `export NPM_GITHUB_TOKEN=<your_classic_pat>`
25
+
26
+ Install dependencies:
27
+
28
+ `bun install`
29
+
30
+ Test:
31
+
32
+ `bun test`
33
+
34
+ Serve dev version:
35
+
36
+ `bun html/index.html`
37
+
38
+ Bundle:
39
+
40
+ `bun run build`
41
+
42
+ **NOTE**: The following tasks use Deno as it excels at these and Bun does not
43
+ currently provide such functionality:
44
+
45
+ Format:
46
+
47
+ `deno fmt`
48
+
49
+ Lint:
50
+
51
+ `deno lint src/ tests/`
52
+
53
+ ## Functional Tests
54
+
55
+ Refer to [functional_tests/README.md](functional_tests/README.md)
56
+
57
+ ## License
58
+
59
+ MIT © Flowscripter
package/build.ts ADDED
@@ -0,0 +1,8 @@
1
+ import bunPluginTailwind from "bun-plugin-tailwind";
2
+
3
+ await Bun.build({
4
+ entrypoints: ["html/index.html"],
5
+ outdir: "dist",
6
+ minify: true,
7
+ plugins: [bunPluginTailwind],
8
+ });
@@ -0,0 +1,25 @@
1
+ ## Webapp Functional Tests
2
+
3
+ #### Setup
4
+
5
+ Ensure the webapp is bundled:
6
+
7
+ bun run build
8
+
9
+ Install requirements:
10
+
11
+ pip3 install -r pip-requirements.txt
12
+
13
+ Install `geckodriver` from https://github.com/mozilla/geckodriver/releases and
14
+ ensure the executable is in your _PATH_.
15
+
16
+ #### Testing
17
+
18
+ Run the functional tests:
19
+
20
+ behave
21
+
22
+ To run with logging output from the test steps (this is the best set of
23
+ arguments I can find):
24
+
25
+ behave --no-logcapture --no-color --logging-level=DEBUG
@@ -0,0 +1,50 @@
1
+ from behave import fixture, use_fixture
2
+ from selenium.webdriver import Firefox
3
+ from selenium.webdriver import FirefoxOptions
4
+ from http.server import SimpleHTTPRequestHandler
5
+ from functools import partial
6
+ import socketserver
7
+ import threading
8
+ import pathlib
9
+
10
+ address = "127.0.0.1"
11
+ port = 8000
12
+
13
+
14
+ @fixture
15
+ def browser_firefox(context):
16
+ options = FirefoxOptions()
17
+ options.add_argument("-headless")
18
+ context.browser = Firefox(options=options)
19
+ yield context.browser
20
+ context.browser.quit()
21
+
22
+
23
+ @fixture
24
+ def local_webserver(context):
25
+ web_root = pathlib.Path(__file__).parent.parent.parent.joinpath("dist")
26
+
27
+ handler_class = partial(SimpleHTTPRequestHandler, directory=web_root)
28
+
29
+ socketserver.TCPServer.allow_reuse_address = True
30
+
31
+ httpd = socketserver.TCPServer((address, port), handler_class)
32
+
33
+ server_thread = threading.Thread(target=httpd.serve_forever)
34
+ server_thread.daemon = True
35
+ server_thread.start()
36
+
37
+ def shutdown_webserver():
38
+ httpd.shutdown()
39
+ httpd.server_close()
40
+ server_thread.join()
41
+
42
+ context.add_cleanup(shutdown_webserver)
43
+
44
+
45
+ def before_all(context):
46
+ context.config.setup_logging()
47
+ use_fixture(local_webserver, context)
48
+ use_fixture(browser_firefox, context)
49
+ context.address = address
50
+ context.port = port
@@ -0,0 +1,15 @@
1
+ class element_value_is_non_empty(object):
2
+ """An expectation for checking that an element has a text value which is not empty.
3
+
4
+ locator - used to find the element
5
+ returns the WebElement once it has a non empty value
6
+ """
7
+ def __init__(self, locator):
8
+ self.locator = locator
9
+
10
+ def __call__(self, driver):
11
+ element = driver.find_element(*self.locator)
12
+ if len(element.get_property('value')) > 0:
13
+ return element
14
+ else:
15
+ return False
@@ -0,0 +1,30 @@
1
+ from behave import when, then
2
+ from selenium.webdriver.support.expected_conditions import presence_of_element_located
3
+ from selenium.webdriver.support.wait import WebDriverWait
4
+ from selenium.webdriver.common.by import By
5
+ from helper.selenium import element_value_is_non_empty
6
+
7
+ import logging
8
+
9
+ log = logging.getLogger("webapp")
10
+
11
+
12
+ @when('the webapp URL "{page}" is loaded')
13
+ def step_impl(context, page):
14
+ url = "http://{}:{}/{}".format(context.address, context.port, page)
15
+ context.browser.get(url)
16
+
17
+
18
+ @then('the page element with data-testid "{element_id}" should be available')
19
+ def step_impl(context, element_id):
20
+ log.debug('waiting for element "{}"'.format(element_id))
21
+
22
+ try:
23
+ log.debug('waiting for element "{}"'.format(element_id))
24
+ WebDriverWait(context.browser, 3).until(presence_of_element_located((By.CSS_SELECTOR, '[data-testid="{}"]'.format(element_id))))
25
+ except Exception as e:
26
+ log.error('Element not found: {}'.format(e))
27
+ log.debug('Page source: {}'.format(context.browser.page_source))
28
+ log.debug('Current URL: {}'.format(context.browser.current_url))
29
+ raise
30
+
@@ -0,0 +1,5 @@
1
+ Feature: Webapp
2
+
3
+ Scenario: Webapp success
4
+ When the webapp URL "index.html" is loaded
5
+ Then the page element with data-testid "main-content" should be available
@@ -0,0 +1,2 @@
1
+ selenium
2
+ behave
@@ -0,0 +1,126 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg
3
+ id="Layer_1"
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ version="1.1"
6
+ viewBox="220 10 450 450"
7
+ >
8
+ <defs>
9
+ <style>.st0 {
10
+ fill: #08a6e0;
11
+ }
12
+
13
+ .st1 {
14
+ fill: #006fa9;
15
+ }
16
+
17
+ .st2 {
18
+ fill: #0071bb;
19
+ }
20
+
21
+ .st3 {
22
+ fill: #002a53;
23
+ }</style>
24
+ </defs>
25
+ <path
26
+ class="st3"
27
+ d="M421.2,445.7c0,6.2-5,11.2-11.2,11.2s-11.2-5-11.2-11.2,5-11.2,11.2-11.2,11.2,5,11.2,11.2"
28
+ />
29
+ <g>
30
+ <rect class="st2" x="292.5" y="348.4" width="39.2" height="39.2" />
31
+ <rect class="st1" x="292.5" y="230.9" width="39.2" height="39.2" />
32
+ <rect class="st2" x="292.5" y="113.4" width="39.2" height="39.2" />
33
+ <path
34
+ class="st2"
35
+ d="M292.5,74.2h39.2v-19.6c0-10.8-8.8-19.6-19.6-19.6s-19.6,8.8-19.6,19.6v19.6Z"
36
+ />
37
+ <path
38
+ class="st2"
39
+ d="M463.1,348.4h0c10.8,0,19.6-8.8,19.6-19.6v-19.6h-39.2v19.6c0,10.8,8.8,19.6,19.6,19.6"
40
+ />
41
+ <rect class="st2" x="443.6" y="191.7" width="39.2" height="39.2" />
42
+ <path
43
+ class="st1"
44
+ d="M443.6,152.6h39.2v-19.6c0-10.8-8.8-19.6-19.6-19.6s-19.6,8.8-19.6,19.6v19.6Z"
45
+ />
46
+ <rect class="st2" x="342.8" y="270.1" width="39.2" height="39.2" />
47
+ <rect class="st2" x="342.8" y="152.6" width="39.2" height="39.2" />
48
+ <rect class="st2" x="393.2" y="211.3" width="39.2" height="39.2" />
49
+ <path
50
+ class="st2"
51
+ d="M393.2,133h39.2v-19.6c0-10.8-8.8-19.6-19.6-19.6s-19.6,8.8-19.6,19.6v19.6Z"
52
+ />
53
+ <rect class="st3" x="292.5" y="309.2" width="39.2" height="39.2" />
54
+ <rect class="st3" x="292.5" y="191.7" width="39.2" height="39.2" />
55
+ <rect class="st3" x="292.5" y="74.2" width="39.2" height="39.2" />
56
+ <rect class="st3" x="443.6" y="270.1" width="39.2" height="39.2" />
57
+ <rect class="st3" x="443.6" y="152.6" width="39.2" height="39.2" />
58
+ <path
59
+ class="st3"
60
+ d="M362.4,387.6h0c10.8,0,19.6-8.8,19.6-19.6v-19.6h-39.2v19.6c0,10.8,8.8,19.6,19.6,19.6"
61
+ />
62
+ <rect class="st3" x="342.8" y="230.9" width="39.2" height="39.2" />
63
+ <rect class="st3" x="393.2" y="172.1" width="39.2" height="39.2" />
64
+ <rect class="st2" x="393.2" y="289.6" width="39.2" height="39.2" />
65
+ <rect class="st3" x="393.2" y="250.5" width="39.2" height="39.2" />
66
+ <rect class="st3" x="342.8" y="113.4" width="39.2" height="39.2" />
67
+ <path
68
+ class="st0"
69
+ d="M312.1,426.7h0c10.8,0,19.6-8.8,19.6-19.6v-19.6h-39.2v19.6c0,10.8,8.8,19.6,19.6,19.6"
70
+ />
71
+ <rect class="st0" x="292.5" y="270.1" width="39.2" height="39.2" />
72
+ <rect class="st0" x="292.5" y="152.6" width="39.2" height="39.2" />
73
+ <rect class="st0" x="443.6" y="230.9" width="39.2" height="39.2" />
74
+ <rect class="st0" x="342.8" y="309.2" width="39.2" height="39.2" />
75
+ <path
76
+ class="st3"
77
+ d="M563.9,270.1h0c10.8,0,19.6-8.8,19.6-19.6v-19.6h-39.2v19.6c0,10.8,8.8,19.6,19.6,19.6"
78
+ />
79
+ <path
80
+ class="st2"
81
+ d="M544.3,230.9h39.2v-19.6c0-10.8-8.8-19.6-19.6-19.6s-19.6,8.8-19.6,19.6v19.6Z"
82
+ />
83
+ <g>
84
+ <rect class="st2" x="493.9" y="230.9" width="39.2" height="39.2" />
85
+ <path
86
+ class="st3"
87
+ d="M513.5,152.6h0c-10.8,0-19.6,8.8-19.6,19.6v19.6h39.2v-19.6c0-10.8-8.8-19.6-19.6-19.6"
88
+ />
89
+ <path
90
+ class="st3"
91
+ d="M533.1,270.1h-39.2v19.6c0,10.8,8.8,19.6,19.6,19.6s19.6-8.8,19.6-19.6v-19.6Z"
92
+ />
93
+ <rect class="st0" x="493.9" y="191.7" width="39.2" height="39.2" />
94
+ </g>
95
+ <rect class="st0" x="342.8" y="191.7" width="39.2" height="39.2" />
96
+ <path
97
+ class="st3"
98
+ d="M412.8,368h0c10.8,0,19.6-8.8,19.6-19.6v-19.6h-39.2v19.6c0,10.8,8.8,19.6,19.6,19.6"
99
+ />
100
+ <rect class="st0" x="393.2" y="133" width="39.2" height="39.2" />
101
+ <path
102
+ class="st0"
103
+ d="M342.8,113.4h39.2v-19.6c0-10.8-8.8-19.6-19.6-19.6s-19.6,8.8-19.6,19.6v19.6Z"
104
+ />
105
+ <path
106
+ class="st3"
107
+ d="M482.7,88.2c0,10.8-8.8,19.6-19.6,19.6s-19.6-8.8-19.6-19.6,8.8-19.6,19.6-19.6,19.6,8.8,19.6,19.6"
108
+ />
109
+ <path
110
+ class="st1"
111
+ d="M432.4,398.1c0,10.8-8.8,19.6-19.6,19.6s-19.6-8.8-19.6-19.6,8.8-19.6,19.6-19.6,19.6,8.8,19.6,19.6"
112
+ />
113
+ <path
114
+ class="st0"
115
+ d="M521.9,85.4c0,6.2-5,11.2-11.2,11.2s-11.2-5-11.2-11.2,5-11.2,11.2-11.2,11.2,5,11.2,11.2"
116
+ />
117
+ <path
118
+ class="st1"
119
+ d="M505.1,49c0,7.7-6.3,14-14,14s-14-6.3-14-14,6.3-14,14-14,14,6.3,14,14"
120
+ />
121
+ <path
122
+ class="st0"
123
+ d="M465.9,426.1c0,7.7-6.3,14-14,14s-14-6.3-14-14,6.3-14,14-14,14,6.3,14,14"
124
+ />
125
+ </g>
126
+ </svg>
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="light">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link rel="stylesheet" href="style.css" />
7
+ <link rel="icon" type="image/svg+xml" href="favicon.svg" />
8
+ <title>MPEG SDL Editor</title>
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ <script type="module" src="../src/main.tsx"></script>
13
+ </body>
14
+ </html>
package/html/style.css ADDED
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss";
2
+ @plugin "daisyui";
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@mpeggroup/mpeg-sdl-editor",
3
+ "description": "ISO/IEC 14496-34 Syntactic Description Language (MPEG SDL) web based editor",
4
+ "homepage": "https://github.com/MPEGGroup/mpeg-sdl-editor#readme",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/MPEGGroup/mpeg-sdl-editor.git"
8
+ },
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "bun",
12
+ "mpeg",
13
+ "sdl",
14
+ "parser",
15
+ "editor"
16
+ ],
17
+ "type": "module",
18
+ "version": "1.3.1",
19
+ "scripts": {
20
+ "build": "bun build.ts"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "devDependencies": {
26
+ "@happy-dom/global-registrator": "20.9.0",
27
+ "@testing-library/dom": "10.4.1",
28
+ "@testing-library/react": "16.3.2",
29
+ "@types/bun": "1.3.13",
30
+ "bun-plugin-tailwind": "0.1.2",
31
+ "happy-dom": "20.9.0"
32
+ },
33
+ "peerDependencies": {
34
+ "typescript": "6.0.3",
35
+ "@types/react": "19.2.14",
36
+ "@types/react-dom": "19.2.3"
37
+ },
38
+ "dependencies": {
39
+ "@codemirror/language": "6.12.1",
40
+ "@codemirror/lint": "6.9.2",
41
+ "@lezer/common": "1.5.0",
42
+ "@lezer/highlight": "1.2.3",
43
+ "@mpeggroup/mpeg-sdl-parser": "4.1.1",
44
+ "@types/wicg-file-system-access": "2023.10.7",
45
+ "@uiw/codemirror-theme-vscode": "4.25.9",
46
+ "@uiw/react-codemirror": "4.25.9",
47
+ "daisyui": "5.5.19",
48
+ "react": "19.2.5",
49
+ "react-dom": "19.2.5",
50
+ "tailwindcss": "4.2.4"
51
+ },
52
+ "overrides": {
53
+ "@codemirror/language": "6.12.1",
54
+ "@codemirror/lint": "6.9.2",
55
+ "@codemirror/state": "6.5.4",
56
+ "@codemirror/view": "6.39.9",
57
+ "@lezer/common": "1.5.0",
58
+ "@lezer/highlight": "1.2.3",
59
+ "@lezer/lr": "1.4.7"
60
+ }
61
+ }
package/src/App.css ADDED
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;