@greenpandastudios/aug-cli 0.19.0
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.
- package/LICENSE +21 -0
- package/README.md +13 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/bin/aug.mjs +3 -0
- package/docs/api/crypto.md +351 -0
- package/docs/api/io.md +207 -0
- package/docs/api/json.md +21 -0
- package/docs/api/memory.md +109 -0
- package/docs/api/time.md +54 -0
- package/docs/api/web.md +184 -0
- package/docs/assets/benchmarks/execution.svg +2978 -0
- package/docs/assets/benchmarks/http.svg +1674 -0
- package/docs/assets/benchmarks/improvements.svg +2315 -0
- package/docs/assets/benchmarks/memory.svg +1891 -0
- package/docs/benchmark-baseline.json +1087 -0
- package/docs/benchmark-results.json +91123 -0
- package/docs/benchmarks.json +38 -0
- package/docs/compatibility.md +42 -0
- package/docs/concurrency-implementation.md +18 -0
- package/docs/diagnostics.md +97 -0
- package/docs/docker.md +35 -0
- package/docs/example-projects.json +26 -0
- package/docs/examples/approved-design/counters.md +253 -0
- package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/approved-design/domain/app.md +165 -0
- package/docs/examples/approved-design/domain/export.md +83 -0
- package/docs/examples/approved-design/domain/models.md +80 -0
- package/docs/examples/approved-design/domain/numbers.md +248 -0
- package/docs/examples/approved-design/index.md +39 -0
- package/docs/examples/approved-design/main-yaml.md +24 -0
- package/docs/examples/approved-design/main.md +215 -0
- package/docs/examples/benchmark/index.md +33 -0
- package/docs/examples/benchmark/main-yaml.md +17 -0
- package/docs/examples/benchmark/main.md +117 -0
- package/docs/examples/cli-args/index.md +32 -0
- package/docs/examples/cli-args/main.md +107 -0
- package/docs/examples/collections/index.md +32 -0
- package/docs/examples/collections/main.md +118 -0
- package/docs/examples/collections-benchmark/index.md +34 -0
- package/docs/examples/collections-benchmark/main.md +115 -0
- package/docs/examples/cpu-benchmark/index.md +34 -0
- package/docs/examples/cpu-benchmark/main.md +90 -0
- package/docs/examples/developer-workflow/calculator.md +357 -0
- package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/developer-workflow/index.md +37 -0
- package/docs/examples/developer-workflow/logging/console.md +124 -0
- package/docs/examples/developer-workflow/logging/export.md +70 -0
- package/docs/examples/developer-workflow/logging/logger.md +111 -0
- package/docs/examples/developer-workflow/main.md +172 -0
- package/docs/examples/drop/index.md +33 -0
- package/docs/examples/drop/main.md +85 -0
- package/docs/examples/drop/resource.md +95 -0
- package/docs/examples/errors/errors.md +85 -0
- package/docs/examples/errors/index.md +33 -0
- package/docs/examples/errors/main.md +92 -0
- package/docs/examples/ffi/index.md +33 -0
- package/docs/examples/ffi/main.md +75 -0
- package/docs/examples/ffi/native.md +93 -0
- package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/generic-di/index.md +33 -0
- package/docs/examples/generic-di/main.md +111 -0
- package/docs/examples/generic-di/types.md +180 -0
- package/docs/examples/generics/index.md +33 -0
- package/docs/examples/generics/main.md +120 -0
- package/docs/examples/generics/types.md +189 -0
- package/docs/examples/hello/app/export.md +67 -0
- package/docs/examples/hello/app/greeter.md +190 -0
- package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/hello/index.md +37 -0
- package/docs/examples/hello/logging/console.md +121 -0
- package/docs/examples/hello/logging/export.md +71 -0
- package/docs/examples/hello/logging/logger.md +120 -0
- package/docs/examples/hello/main.md +115 -0
- package/docs/examples/http-benchmark/index.md +35 -0
- package/docs/examples/http-benchmark/main.md +79 -0
- package/docs/examples/http-benchmark/routes.md +88 -0
- package/docs/examples/index.md +60 -0
- package/docs/examples/interceptors/app.md +250 -0
- package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/interceptors/index.md +35 -0
- package/docs/examples/interceptors/interceptors.md +284 -0
- package/docs/examples/interceptors/logging.md +155 -0
- package/docs/examples/interceptors/main.md +162 -0
- package/docs/examples/json-benchmark/data.md +71 -0
- package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +103 -0
- package/docs/examples/json-benchmark/index.md +35 -0
- package/docs/examples/json-benchmark/main.md +131 -0
- package/docs/examples/new-syntax/console.md +118 -0
- package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/new-syntax/greeter.md +145 -0
- package/docs/examples/new-syntax/index.md +36 -0
- package/docs/examples/new-syntax/logger.md +111 -0
- package/docs/examples/new-syntax/main.md +135 -0
- package/docs/examples/new-syntax/math.md +79 -0
- package/docs/examples/oidc-login/client/contracts.md +151 -0
- package/docs/examples/oidc-login/client/endpoints.md +263 -0
- package/docs/examples/oidc-login/client/export.md +107 -0
- package/docs/examples/oidc-login/client/login.md +515 -0
- package/docs/examples/oidc-login/client/logout.md +249 -0
- package/docs/examples/oidc-login/client/protocol.md +595 -0
- package/docs/examples/oidc-login/client/session.md +297 -0
- package/docs/examples/oidc-login/client/views.md +144 -0
- package/docs/examples/oidc-login/common/export.md +115 -0
- package/docs/examples/oidc-login/common/headers.md +162 -0
- package/docs/examples/oidc-login/common/keys.md +336 -0
- package/docs/examples/oidc-login/common/settings.md +116 -0
- package/docs/examples/oidc-login/common/views.md +103 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +925 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +434 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +103 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +374 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +150 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +532 -0
- package/docs/examples/oidc-login/index.md +57 -0
- package/docs/examples/oidc-login/main-yaml.md +28 -0
- package/docs/examples/oidc-login/main.md +283 -0
- package/docs/examples/oidc-login/provider/authorization.md +457 -0
- package/docs/examples/oidc-login/provider/contracts.md +267 -0
- package/docs/examples/oidc-login/provider/credentials.md +148 -0
- package/docs/examples/oidc-login/provider/discovery.md +215 -0
- package/docs/examples/oidc-login/provider/export.md +131 -0
- package/docs/examples/oidc-login/provider/token.md +364 -0
- package/docs/examples/oidc-login/provider/userinfo.md +228 -0
- package/docs/examples/oidc-login/provider/views.md +137 -0
- package/docs/examples/ownership/counter.md +140 -0
- package/docs/examples/ownership/index.md +33 -0
- package/docs/examples/ownership/main.md +90 -0
- package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/ownership-transfer/index.md +33 -0
- package/docs/examples/ownership-transfer/main.md +125 -0
- package/docs/examples/ownership-transfer/resource.md +150 -0
- package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +117 -0
- package/docs/examples/packages-app/index.md +34 -0
- package/docs/examples/packages-app/main-yaml.md +18 -0
- package/docs/examples/packages-app/main.md +80 -0
- package/docs/examples/packages-math/aug-package-json.md +24 -0
- package/docs/examples/packages-math/index.md +36 -0
- package/docs/examples/packages-math/package-json.md +25 -0
- package/docs/examples/packages-math/src/arithmetic.md +121 -0
- package/docs/examples/packages-math/src/export.md +63 -0
- package/docs/examples/startup-benchmark/index.md +34 -0
- package/docs/examples/startup-benchmark/main.md +68 -0
- package/docs/examples/visibility/counter.md +142 -0
- package/docs/examples/visibility/index.md +33 -0
- package/docs/examples/visibility/main.md +96 -0
- package/docs/examples.json +47 -0
- package/docs/getting-started.md +5 -0
- package/docs/grammar.md +136 -0
- package/docs/implementation-map.md +106 -0
- package/docs/index.md +46 -0
- package/docs/language-conformance.md +30 -0
- package/docs/language-constructs.md +1461 -0
- package/docs/language-design-audit.md +147 -0
- package/docs/maintaining-docs.md +43 -0
- package/docs/packages.md +184 -0
- package/docs/performance.md +535 -0
- package/docs/production-readiness.md +39 -0
- package/docs/reference.md +361 -0
- package/docs/release-review.md +23 -0
- package/docs/releasing.md +79 -0
- package/docs/roadmap.md +13 -0
- package/docs/specifications.md +86 -0
- package/docs/testing.md +120 -0
- package/docs/tooling.md +197 -0
- package/docs/web-implementation-plan.md +39 -0
- package/docs/web-library-gaps.md +27 -0
- package/docs/web.md +197 -0
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/approved-design/.aug-spec/manifest.json +14 -0
- package/examples/approved-design/counters.aug +22 -0
- package/examples/approved-design/counters.aug.md +177 -0
- package/examples/approved-design/domain/app.aug +12 -0
- package/examples/approved-design/domain/app.aug.md +97 -0
- package/examples/approved-design/domain/export.aug +5 -0
- package/examples/approved-design/domain/export.aug.md +25 -0
- package/examples/approved-design/domain/models.aug +2 -0
- package/examples/approved-design/domain/models.aug.md +30 -0
- package/examples/approved-design/domain/numbers.aug +29 -0
- package/examples/approved-design/domain/numbers.aug.md +141 -0
- package/examples/approved-design/main.aug +26 -0
- package/examples/approved-design/main.aug.md +108 -0
- package/examples/approved-design/main.yaml +8 -0
- package/examples/benchmark/.aug-spec/manifest.json +7 -0
- package/examples/benchmark/main.aug +17 -0
- package/examples/benchmark/main.aug.md +43 -0
- package/examples/benchmark/main.yaml +1 -0
- package/examples/cli-args/.aug-spec/manifest.json +7 -0
- package/examples/cli-args/main.aug +15 -0
- package/examples/cli-args/main.aug.md +38 -0
- package/examples/collections/.aug-spec/manifest.json +7 -0
- package/examples/collections/main.aug +18 -0
- package/examples/collections/main.aug.md +43 -0
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/developer-workflow/.aug-spec/manifest.json +13 -0
- package/examples/developer-workflow/calculator.aug +55 -0
- package/examples/developer-workflow/calculator.aug.md +228 -0
- package/examples/developer-workflow/logging/console.aug +8 -0
- package/examples/developer-workflow/logging/console.aug.md +67 -0
- package/examples/developer-workflow/logging/export.aug +2 -0
- package/examples/developer-workflow/logging/export.aug.md +19 -0
- package/examples/developer-workflow/logging/logger.aug +6 -0
- package/examples/developer-workflow/logging/logger.aug.md +57 -0
- package/examples/developer-workflow/main.aug +25 -0
- package/examples/developer-workflow/main.aug.md +79 -0
- package/examples/drop/.aug-spec/manifest.json +8 -0
- package/examples/drop/main.aug +3 -0
- package/examples/drop/main.aug.md +35 -0
- package/examples/drop/resource.aug +8 -0
- package/examples/drop/resource.aug.md +44 -0
- package/examples/errors/.aug-spec/manifest.json +8 -0
- package/examples/errors/errors.aug +6 -0
- package/examples/errors/errors.aug.md +33 -0
- package/examples/errors/main.aug +7 -0
- package/examples/errors/main.aug.md +36 -0
- package/examples/ffi/.aug-spec/manifest.json +8 -0
- package/examples/ffi/main.aug +2 -0
- package/examples/ffi/main.aug.md +27 -0
- package/examples/ffi/native.aug +6 -0
- package/examples/ffi/native.aug.md +43 -0
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/generic-di/.aug-spec/manifest.json +10 -0
- package/examples/generic-di/main.aug +9 -0
- package/examples/generic-di/main.aug.md +49 -0
- package/examples/generic-di/types.aug +17 -0
- package/examples/generic-di/types.aug.md +124 -0
- package/examples/generics/.aug-spec/manifest.json +8 -0
- package/examples/generics/main.aug +9 -0
- package/examples/generics/main.aug.md +58 -0
- package/examples/generics/types.aug +19 -0
- package/examples/generics/types.aug.md +132 -0
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/hello/.aug-spec/manifest.json +14 -0
- package/examples/hello/app/export.aug +1 -0
- package/examples/hello/app/export.aug.md +17 -0
- package/examples/hello/app/greeter.aug +22 -0
- package/examples/hello/app/greeter.aug.md +109 -0
- package/examples/hello/logging/console.aug +7 -0
- package/examples/hello/logging/console.aug.md +65 -0
- package/examples/hello/logging/export.aug +2 -0
- package/examples/hello/logging/export.aug.md +19 -0
- package/examples/hello/logging/logger.aug +9 -0
- package/examples/hello/logging/logger.aug.md +59 -0
- package/examples/hello/main.aug +9 -0
- package/examples/hello/main.aug.md +49 -0
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/interceptors/.aug-spec/manifest.json +12 -0
- package/examples/interceptors/app.aug +28 -0
- package/examples/interceptors/app.aug.md +162 -0
- package/examples/interceptors/interceptors.aug +40 -0
- package/examples/interceptors/interceptors.aug.md +180 -0
- package/examples/interceptors/logging.aug +12 -0
- package/examples/interceptors/logging.aug.md +96 -0
- package/examples/interceptors/main.aug +22 -0
- package/examples/interceptors/main.aug.md +76 -0
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/new-syntax/.aug-spec/manifest.json +13 -0
- package/examples/new-syntax/console.aug +7 -0
- package/examples/new-syntax/console.aug.md +63 -0
- package/examples/new-syntax/greeter.aug +10 -0
- package/examples/new-syntax/greeter.aug.md +89 -0
- package/examples/new-syntax/logger.aug +6 -0
- package/examples/new-syntax/logger.aug.md +57 -0
- package/examples/new-syntax/main.aug +12 -0
- package/examples/new-syntax/main.aug.md +64 -0
- package/examples/new-syntax/math.aug +3 -0
- package/examples/new-syntax/math.aug.md +29 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug +73 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +791 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug +68 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +266 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug +6 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +55 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug +45 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +250 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug +11 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +96 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug +58 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +420 -0
- package/examples/oidc-login/.aug-spec/manifest.json +40 -0
- package/examples/oidc-login/README.md +29 -0
- package/examples/oidc-login/client/contracts.aug +7 -0
- package/examples/oidc-login/client/contracts.aug.md +80 -0
- package/examples/oidc-login/client/endpoints.aug +21 -0
- package/examples/oidc-login/client/endpoints.aug.md +161 -0
- package/examples/oidc-login/client/export.aug +7 -0
- package/examples/oidc-login/client/export.aug.md +29 -0
- package/examples/oidc-login/client/login.aug +58 -0
- package/examples/oidc-login/client/login.aug.md +331 -0
- package/examples/oidc-login/client/logout.aug +18 -0
- package/examples/oidc-login/client/logout.aug.md +150 -0
- package/examples/oidc-login/client/protocol.aug +106 -0
- package/examples/oidc-login/client/protocol.aug.md +326 -0
- package/examples/oidc-login/client/session.aug +34 -0
- package/examples/oidc-login/client/session.aug.md +155 -0
- package/examples/oidc-login/client/views.aug +21 -0
- package/examples/oidc-login/client/views.aug.md +68 -0
- package/examples/oidc-login/common/export.aug +9 -0
- package/examples/oidc-login/common/export.aug.md +33 -0
- package/examples/oidc-login/common/headers.aug +11 -0
- package/examples/oidc-login/common/headers.aug.md +79 -0
- package/examples/oidc-login/common/keys.aug +37 -0
- package/examples/oidc-login/common/keys.aug.md +207 -0
- package/examples/oidc-login/common/settings.aug +4 -0
- package/examples/oidc-login/common/settings.aug.md +47 -0
- package/examples/oidc-login/common/views.aug +16 -0
- package/examples/oidc-login/common/views.aug.md +34 -0
- package/examples/oidc-login/main.aug +39 -0
- package/examples/oidc-login/main.aug.md +166 -0
- package/examples/oidc-login/main.yaml +12 -0
- package/examples/oidc-login/provider/authorization.aug +59 -0
- package/examples/oidc-login/provider/authorization.aug.md +264 -0
- package/examples/oidc-login/provider/contracts.aug +15 -0
- package/examples/oidc-login/provider/contracts.aug.md +193 -0
- package/examples/oidc-login/provider/credentials.aug +10 -0
- package/examples/oidc-login/provider/credentials.aug.md +64 -0
- package/examples/oidc-login/provider/discovery.aug +13 -0
- package/examples/oidc-login/provider/discovery.aug.md +133 -0
- package/examples/oidc-login/provider/export.aug +13 -0
- package/examples/oidc-login/provider/export.aug.md +41 -0
- package/examples/oidc-login/provider/token.aug +37 -0
- package/examples/oidc-login/provider/token.aug.md +223 -0
- package/examples/oidc-login/provider/userinfo.aug +26 -0
- package/examples/oidc-login/provider/userinfo.aug.md +104 -0
- package/examples/oidc-login/provider/views.aug +18 -0
- package/examples/oidc-login/provider/views.aug.md +63 -0
- package/examples/ownership/.aug-spec/manifest.json +8 -0
- package/examples/ownership/counter.aug +14 -0
- package/examples/ownership/counter.aug.md +85 -0
- package/examples/ownership/main.aug +4 -0
- package/examples/ownership/main.aug.md +38 -0
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/ownership-transfer/.aug-spec/manifest.json +10 -0
- package/examples/ownership-transfer/main.aug +9 -0
- package/examples/ownership-transfer/main.aug.md +63 -0
- package/examples/ownership-transfer/resource.aug +16 -0
- package/examples/ownership-transfer/resource.aug.md +89 -0
- package/examples/packages/README.md +15 -0
- package/examples/packages/app/.aug-spec/manifest.json +9 -0
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +9 -0
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +63 -0
- package/examples/packages/app/main.aug +2 -0
- package/examples/packages/app/main.aug.md +33 -0
- package/examples/packages/app/main.yaml +2 -0
- package/examples/packages/math/.aug-spec/manifest.json +8 -0
- package/examples/packages/math/README.md +3 -0
- package/examples/packages/math/aug-package.json +8 -0
- package/examples/packages/math/package.json +9 -0
- package/examples/packages/math/src/arithmetic.aug +8 -0
- package/examples/packages/math/src/arithmetic.aug.md +63 -0
- package/examples/packages/math/src/export.aug +1 -0
- package/examples/packages/math/src/export.aug.md +17 -0
- package/examples/visibility/.aug-spec/manifest.json +8 -0
- package/examples/visibility/counter.aug +14 -0
- package/examples/visibility/counter.aug.md +87 -0
- package/examples/visibility/main.aug +7 -0
- package/examples/visibility/main.aug.md +39 -0
- package/package.json +50 -0
- package/runtime/aug_crypto.c +121 -0
- package/runtime/aug_html.c +93 -0
- package/runtime/aug_http.c +829 -0
- package/runtime/aug_json.c +165 -0
- package/runtime/aug_runtime.c +792 -0
- package/runtime/aug_runtime.h +245 -0
- package/runtime/aug_tasks.c +172 -0
- package/runtime/aug_time.c +5 -0
- package/runtime/aug_values.c +80 -0
- package/scripts/bootstrap-native.mjs +121 -0
- package/scripts/native-dependencies.lock.json +65 -0
- package/scripts/native-home.mjs +11 -0
- package/src/actions.js +109 -0
- package/src/ast.js +19 -0
- package/src/builtins.js +93 -0
- package/src/checker.js +2896 -0
- package/src/cli.js +344 -0
- package/src/codegen.js +1159 -0
- package/src/config.js +149 -0
- package/src/continuation.js +110 -0
- package/src/di.js +24 -0
- package/src/documentation.js +27 -0
- package/src/editor.js +782 -0
- package/src/effects.js +29 -0
- package/src/fixes.js +222 -0
- package/src/formatter.js +296 -0
- package/src/freshness.js +154 -0
- package/src/help.js +212 -0
- package/src/html.js +27 -0
- package/src/http-policies.js +90 -0
- package/src/inference.js +16 -0
- package/src/interceptors.js +70 -0
- package/src/javadoc.js +67 -0
- package/src/lexer.js +199 -0
- package/src/libraries.js +31 -0
- package/src/lsp.js +180 -0
- package/src/native.js +144 -0
- package/src/navigation.js +162 -0
- package/src/openapi.js +220 -0
- package/src/ownership.js +232 -0
- package/src/package-manager.js +299 -0
- package/src/parser.js +1155 -0
- package/src/policies.js +130 -0
- package/src/project-init.js +19 -0
- package/src/project.js +292 -0
- package/src/schemas.js +62 -0
- package/src/semantic.js +255 -0
- package/src/spec.js +738 -0
- package/src/testing.js +186 -0
- package/src/types.js +10 -0
package/src/freshness.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/** Conservative proof that successful returns preserve constructor freshness. */
|
|
2
|
+
export function returnsFresh(body, fields, freshCall) {
|
|
3
|
+
let valid = true;
|
|
4
|
+
const fresh = (expr, locals) => expr.kind === 'name' ?
|
|
5
|
+
locals.get(expr.name) === true : freshCall(expr);
|
|
6
|
+
const escape = (expr, locals) => {
|
|
7
|
+
if (expr.kind === 'start') {
|
|
8
|
+
escape(expr.call, locals);
|
|
9
|
+
}
|
|
10
|
+
else if (expr.kind === 'wait')
|
|
11
|
+
expr.tasks.forEach(task => escape(task, locals));
|
|
12
|
+
else if (expr.kind === 'handle' && expr.call.kind === 'call')
|
|
13
|
+
expr.call.args.forEach(child => escape(child, locals));
|
|
14
|
+
else if (expr.kind === 'markup')
|
|
15
|
+
[...expr.attributes.map(attribute => attribute.value), ...expr.children].forEach(child => escape(child, locals));
|
|
16
|
+
else if (expr.kind === 'collection') {
|
|
17
|
+
if (expr.items.some(item => fresh(item, locals)))
|
|
18
|
+
for (const name of locals.keys())
|
|
19
|
+
locals.set(name, false);
|
|
20
|
+
expr.items.forEach(item => escape(item, locals));
|
|
21
|
+
}
|
|
22
|
+
else if (expr.kind === 'call') {
|
|
23
|
+
const isRead = expr.callee.kind === 'name' && ['next', 'print'].includes(expr.callee.name);
|
|
24
|
+
if (!isRead && expr.args.some(arg => fresh(arg, locals)))
|
|
25
|
+
for (const name of locals.keys())
|
|
26
|
+
locals.set(name, false);
|
|
27
|
+
expr.args.forEach(arg => escape(arg, locals));
|
|
28
|
+
}
|
|
29
|
+
else if (expr.kind === 'binary') {
|
|
30
|
+
escape(expr.left, locals);
|
|
31
|
+
escape(expr.right, locals);
|
|
32
|
+
}
|
|
33
|
+
else if (expr.kind === 'unary')
|
|
34
|
+
escape(expr.value, locals);
|
|
35
|
+
else if (expr.kind === 'member')
|
|
36
|
+
escape(expr.object, locals);
|
|
37
|
+
};
|
|
38
|
+
const walk = (statements, locals) => {
|
|
39
|
+
for (const stmt of statements) {
|
|
40
|
+
if (stmt.kind === 'return') {
|
|
41
|
+
if (stmt.value)
|
|
42
|
+
escape(stmt.value, locals);
|
|
43
|
+
if (!stmt.value || !fresh(stmt.value, locals))
|
|
44
|
+
valid = false;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (stmt.kind === 'throw') {
|
|
48
|
+
escape(stmt.value, locals);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (stmt.kind === 'expr') {
|
|
52
|
+
escape(stmt.expr, locals);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (stmt.kind === 'freeze') {
|
|
56
|
+
locals.set(stmt.name, false);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (stmt.kind === 'serve') {
|
|
60
|
+
escape(stmt.port, locals);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (stmt.kind === 'destructure') {
|
|
64
|
+
escape(stmt.value, locals);
|
|
65
|
+
stmt.names.forEach(name => locals.set(name, false));
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (stmt.kind === 'for') {
|
|
69
|
+
escape(stmt.iterable, locals);
|
|
70
|
+
const inside = new Map(locals);
|
|
71
|
+
stmt.names.forEach(name => inside.set(name, false));
|
|
72
|
+
walk(stmt.body, inside);
|
|
73
|
+
for (const name of locals.keys())
|
|
74
|
+
if (inside.get(name) !== true)
|
|
75
|
+
locals.set(name, false);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (stmt.kind === 'match') {
|
|
79
|
+
escape(stmt.value, locals);
|
|
80
|
+
const states = stmt.cases.map(() => new Map(locals));
|
|
81
|
+
const continues = stmt.cases.map((clause, index) => walk(clause.body, states[index]));
|
|
82
|
+
if (continues.every(value => !value))
|
|
83
|
+
return false;
|
|
84
|
+
for (const name of locals.keys())
|
|
85
|
+
locals.set(name, states.every((state, index) => !continues[index] || state.get(name) === true));
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (stmt.kind === 'assign') {
|
|
89
|
+
escape(stmt.value, locals);
|
|
90
|
+
const value = fresh(stmt.value, locals);
|
|
91
|
+
if (stmt.target.kind === 'name' && !fields.has(stmt.target.name))
|
|
92
|
+
locals.set(stmt.target.name, value);
|
|
93
|
+
else if (value)
|
|
94
|
+
for (const name of locals.keys())
|
|
95
|
+
locals.set(name, false);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (stmt.kind === 'if') {
|
|
99
|
+
escape(stmt.test, locals);
|
|
100
|
+
if (stmt.test.kind === 'literal' && typeof stmt.test.value === 'boolean') {
|
|
101
|
+
if (!walk(stmt.test.value ? stmt.then : stmt.otherwise, locals))
|
|
102
|
+
return false;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const left = new Map(locals), right = new Map(locals);
|
|
106
|
+
const leftContinues = walk(stmt.then, left), rightContinues = walk(stmt.otherwise, right);
|
|
107
|
+
if (!leftContinues && !rightContinues)
|
|
108
|
+
return false;
|
|
109
|
+
for (const name of locals.keys())
|
|
110
|
+
locals.set(name, (!leftContinues || left.get(name) === true) && (!rightContinues || right.get(name) === true));
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (stmt.kind === 'try') {
|
|
114
|
+
if (stmt.always) {
|
|
115
|
+
const cleanup = new Map(locals);
|
|
116
|
+
walk(stmt.always, cleanup);
|
|
117
|
+
for (const name of locals.keys())
|
|
118
|
+
if (!cleanup.get(name))
|
|
119
|
+
locals.set(name, false);
|
|
120
|
+
}
|
|
121
|
+
const states = [new Map(locals), ...stmt.catches.map(() => new Map(locals))];
|
|
122
|
+
const continues = [walk(stmt.body, states[0]), ...stmt.catches.map((clause, i) => walk(clause.body, states[i + 1]))];
|
|
123
|
+
if (continues.every(value => !value))
|
|
124
|
+
return false;
|
|
125
|
+
for (const name of locals.keys())
|
|
126
|
+
locals.set(name, states.every((state, index) => !continues[index] || state.get(name) === true));
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (stmt.kind === 'while') {
|
|
130
|
+
if (stmt.test.kind === 'literal' && stmt.test.value === false)
|
|
131
|
+
continue;
|
|
132
|
+
escape(stmt.test, locals);
|
|
133
|
+
const inside = new Map(locals);
|
|
134
|
+
walk(stmt.body, inside);
|
|
135
|
+
for (const name of locals.keys())
|
|
136
|
+
if (inside.get(name) !== true)
|
|
137
|
+
locals.set(name, false);
|
|
138
|
+
if (stmt.test.kind === 'literal' && stmt.test.value === true)
|
|
139
|
+
return false;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (stmt.kind === 'yield') {
|
|
143
|
+
escape(stmt.value, locals);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (!walk(stmt.body, locals))
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
};
|
|
151
|
+
if (walk(body, new Map()))
|
|
152
|
+
valid = false;
|
|
153
|
+
return valid;
|
|
154
|
+
}
|
package/src/help.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { builtinFunctions } from "./builtins.js";
|
|
2
|
+
const keyword = (detail, documentation) => ({ detail, documentation, category: 'keyword' });
|
|
3
|
+
const type = (detail, documentation) => ({ detail, documentation, category: 'type' });
|
|
4
|
+
const fn = (detail, documentation) => ({ detail, documentation, category: 'function' });
|
|
5
|
+
const operator = (detail, documentation) => ({ detail, documentation, category: 'operator' });
|
|
6
|
+
export const languageHelp = {
|
|
7
|
+
RequireLogin: { category: 'tag', detail: '[RequireLogin(authentication=auth)]', documentation: 'Verify credentials before typed body decoding. Map auth to an explicit resolve Authentication parameter and declare uses auth.authenticate. null produces 401; the adapter validates the credential. HTTP policies precede custom parameter interceptors.' },
|
|
8
|
+
RequirePermission: { category: 'tag', detail: '[RequirePermission(authentication=auth, authorization=permissions, permission="users.read")]', documentation: 'Authenticate the request and authorize one literal permission before decoding. Both dependencies are explicit resolve parameters; declare their authenticate and authorize effects. Missing credentials produce 401 and a denied permission produces 403.' },
|
|
9
|
+
LogRequest: { category: 'tag', detail: '[LogRequest(logger=logger)]', documentation: 'Map a resolve RequestLogger parameter and declare uses logger.complete. Observe the final status and monotonic duration after output finishes, or status 499 on disconnect. Layers complete in reverse written order.' },
|
|
10
|
+
RateLimit: { category: 'tag', detail: '[RateLimit(requests=100, seconds=60)]', documentation: 'A bounded per-endpoint, per-peer fixed-window request limit. Uses the transport peer address, never an untrusted forwarding header. Rejected requests return 429 before body decoding. The table has 2048 entries and rejects new identities when full.' },
|
|
11
|
+
Timeout: { category: 'tag', detail: '[Timeout(milliseconds=5000)]', documentation: 'Bound the request and its streaming producer with a monotonic deadline. Before output, return 504. After headers, terminate the stream. Cancellation joins children and runs always cleanup; native C operations finish before cancellation can be observed.' },
|
|
12
|
+
Cors: { category: 'tag', detail: '[Cors(origins=["https://example.test"], headers=["content-type"], credentials=true)]', documentation: 'Allow exact literal HTTP(S) origins and explicit request header names. OPTIONS preflight checks the selected method and headers. Wildcard origins cannot use credentials. Valid responses include CORS and Vary headers; disallowed origins return 403.' },
|
|
13
|
+
Compress: { category: 'tag', detail: '[Compress]', documentation: 'Negotiate gzip from Accept-Encoding, respecting q=0. Buffered output and each bounded stream item are compressed with standard gzip members. Adds Content-Encoding and Vary; backpressure remains active.' },
|
|
14
|
+
HttpTestClient: type('test endpoint getUser client: ...', 'A suite-supplied HTTP pipeline client. request(method="GET", path="/users/1", headers=..., body=...) returns HttpResponse<Bytes>. It exercises routing, decoding, request DI, policies, and serialization without a listening socket. Streaming collection is bounded by web.response_limit. Each it case runs with fresh test bindings.'),
|
|
15
|
+
input: keyword('handle createUser(input from form)', 'Read named form controls into the endpoint’s record input when a browser submits the action. Labels, scalar conversion, optional fields, and server schema validation follow the endpoint contract.'),
|
|
16
|
+
path: keyword('int id from path', 'Bind a required path placeholder by name. A label after the source can select a different wire name: int userId from path "id".'),
|
|
17
|
+
query: keyword('optional string search from query', 'Bind one query parameter. Omitted optional input becomes null; repeated scalar parameters are rejected.'),
|
|
18
|
+
header: keyword('optional string authorization from header "authorization"', 'Bind a case-insensitive HTTP field. Repeated scalar headers are rejected. Headers.all preserves repeated fields explicitly.'),
|
|
19
|
+
body: keyword('User input from body', 'Decode a concrete JSON data type. Malformed JSON returns 400; valid JSON with a wrong schema returns 422; wrong media type returns 415; body limits return 413.'),
|
|
20
|
+
form: keyword('Login input from form', 'Decode named application/x-www-form-urlencoded fields into a record. Unknown or repeated scalar fields are rejected. Typed handle actions supply form data with input from form.'),
|
|
21
|
+
cookie: keyword('optional string session from cookie "session"', 'Bind one named cookie. Missing input is distinct from an empty string, and repeated cookies are rejected.'),
|
|
22
|
+
request: keyword('HttpRequest request from request', 'Receive the immutable raw request when a protocol requires its own binding and error responses.'),
|
|
23
|
+
pure: keyword('extern C value pure operation(...)', 'A trusted native value adapter promises no effects or mutation. The foreign call still belongs inside unsafe; its declared errors remain checked.'),
|
|
24
|
+
optional: keyword('optional T value', 'Allow a value of T or null. Omitted optional inputs and fields become null. Match null and some, or check != null, before reading the value. This is the only optional type spelling; Type? is rejected.'),
|
|
25
|
+
missing: keyword('null', 'The missing keyword is rejected. Use null. An omitted optional value and an explicit null have the same language value; there is no separate missing state.'),
|
|
26
|
+
freeze: keyword('freeze ownValue as immutableValue', 'Consume owned mutable data and share one deeply frozen object. Surviving aliases cannot mutate it. Literal data can be frozen directly.'),
|
|
27
|
+
as: keyword('lock shared as state: ...', 'Name a local value, lock view, or HTTP endpoint. wait for accepts as or to for result names.'),
|
|
28
|
+
endpoint: keyword('endpoint GET "/users/{id}" as getUser(int id from path) returns User', 'Declare a typed HTTP route. Inputs name their wire source; dependencies use resolve. Main explicitly selects which endpoints to serve.'),
|
|
29
|
+
serve: keyword('serve getUser and createUser on port 8080', 'Start the native HTTP server with explicitly imported endpoints. Each request receives a separate DI and task scope.'),
|
|
30
|
+
streams: keyword('endpoint GET "/events" as events() streams ServerEvent<Event>', 'Declare a bounded streaming HTTP response. Yield values in wire order; disconnect cancels the request scope.'),
|
|
31
|
+
yield: keyword('yield value', 'Send a value from a streaming endpoint. Backpressure suspends the producer until the transport can accept it.'),
|
|
32
|
+
handle: keyword('handle updateUser(id=userId, input from form)', 'Describe a deferred call to a served endpoint. Inputs are checked against wire parameters; DI is resolved when the HTTP request runs. onSubmit and onClick accept HttpAction values, with automatic request transport.'),
|
|
33
|
+
start: keyword('task = start loadUsers()', 'Start a child task in a scope. Receiver and arguments evaluate immediately. Scheduled errors are checked at waits and implicit scope joins; an unhandled child error cancels siblings. A captured object cannot be mutated or moved by the parent while the child uses it. When start runs inside a loop, waiting for one result does not release captures from other iterations; the enclosing scope joins them all.'),
|
|
34
|
+
wait: keyword('wait for usersTask and ordersTask as users and orders', 'Wait for scoped tasks without changing result order. A List<Task<T>> produces List<T> and joins every child in the list. Waiting for one dynamically selected task leaves possible siblings captured until their scope joins them. A wait may encounter an unhandled sibling failure. Grouped waits observe all selected children before rethrowing the first failure. Waiting for I/O suspends a task.'),
|
|
35
|
+
always: keyword('try: ... always: ...', 'Run cleanup on success, checked errors, returns and cancellation. Cancellation bypasses ordinary catch blocks; cleanup runs before the scope ends.'),
|
|
36
|
+
lock: keyword('lock sharedValue as state: ...', 'Grant exclusive mutation of Shared<T> for a short block. Waiting, starting tasks, nested locks and I/O are forbidden inside. Unlocking is guaranteed on return or error.'),
|
|
37
|
+
Data: type('Data', 'A constraint for deeply immutable data: primitives, immutable records and frozen data collections. Behavioral objects cannot satisfy it.'),
|
|
38
|
+
Task: type('Task<T>', 'A child computation owned by a scope. wait for reads its result; the scope joins children before releasing dependencies.'),
|
|
39
|
+
Shared: type('Shared<T>', 'Synchronized mutable state. Construction takes a fresh or owned value. Read and mutate the value only through lock shared as state. A child borrowing an owned Shared<T> pins the wrapper until it finishes; the parent cannot move it into another owner while the child uses it.'),
|
|
40
|
+
Bytes: type('Bytes', 'Immutable length-aware binary data. text() validates UTF-8; base64url() emits canonical unpadded URL-safe base64.'),
|
|
41
|
+
Json: type('Json', 'Immutable JSON data. Parse with august.json, decode concrete records with decode<T>(), and stringify with lossless integer handling.'),
|
|
42
|
+
Html: type('Html', 'Checked server markup produced with JSX elements and components. Interpolated text and attributes are escaped automatically.'),
|
|
43
|
+
HttpAction: type('HttpAction', 'An immutable deferred HTTP call created with handle endpoint(...). Bind it to a form onSubmit or button onClick. The browser sends the request; endpoint dependencies and application logic run on the server.'),
|
|
44
|
+
ServerEvent: type('ServerEvent<T>', 'One SSE event containing concrete JSON data, plus optional id, event, and retry milliseconds. CR, LF and NUL are rejected in metadata. The endpoint streams ServerEvent<T> and yields each event under transport backpressure.'),
|
|
45
|
+
Headers: type('Headers', 'Immutable HTTP fields. with adds a checked field; get and all read case-insensitively. Duplicate Set-Cookie values remain separate.'),
|
|
46
|
+
HttpRequest: type('HttpRequest', 'A request supplied through from request. Its method, path, headers and bounded body are explicit. form<T>() allows protocol-specific form errors.'),
|
|
47
|
+
HttpResponse: type('HttpResponse<T>', 'A typed HTTP body with explicit status and headers. HttpResponse(body=value, status=201, headers=headers) constructs a response. Status literals range from 200 to 599; a dynamic status requires handling or declaring HttpError.'),
|
|
48
|
+
record: keyword('record Point(int x, int y)', 'Declare deeply immutable data with labeled construction and structural equality/hashing. Records contain primitives, tuples and other records. An initialize block validates inputs; declare rejected inputs with unless ErrorType.'),
|
|
49
|
+
initialize: keyword('initialize: ...', 'Run constructor work once after header inputs and local fields are initialized, before returning the class or record. Put this block inside the declaration, before class methods. Construction stays pure. Records can validate inputs and raise declared unless errors, but cannot replace immutable fields.'),
|
|
50
|
+
fixture: keyword('fixture example() returns Data: ...', 'Declare reusable test data through an ordinary checked function. Other files must import the fixture explicitly. Its dependencies and capabilities follow the same header contract rules as other functions.'),
|
|
51
|
+
for: keyword('for item in items: ...', 'Traverse a List, Set, homogeneous Tuple, or Map. Map entries are tuples, so for (key, value) in map unpacks them. Iteration snapshots the collection in insertion order and gives elements read-only access.'),
|
|
52
|
+
match: keyword('match value: when ...', 'Choose a checked case. Cover true and false for bool, null and some for nullable values, or add else. Concrete class cases narrow the named value. Duplicate and unreachable cases are rejected.'),
|
|
53
|
+
some: keyword('when some value: ...', 'Match the present case of a nullable value and introduce a read-only non-null name within the case body. Pair it with when null to cover absence explicitly.'),
|
|
54
|
+
shared: keyword('implement Logger with Adapter shared', 'Cache one stateless binding for the process. Sharing stateful instances requires an explicit shared mutable choice. A process binding cannot retain a scoped dependency.'),
|
|
55
|
+
fresh: keyword('implement Counter with CounterImpl fresh', 'Construct a new instance for each resolution. Stateful bindings use this lifetime by default, including objects that retain stateful dependencies.'),
|
|
56
|
+
scoped: keyword('implement Counter with CounterImpl scoped mutable', 'Cache a binding within a composition scope. Nested scope blocks have independent caches and restore the parent cache on exit. Stateful caching requires the explicit mutable choice.'),
|
|
57
|
+
scope: keyword('scope: ...', 'Create a local DI and child-task lifetime. Children join before dependencies are reclaimed; unhandled failures cancel siblings. Scoped references cannot escape. Nested scopes have independent caches.'),
|
|
58
|
+
composition: keyword('composition Services: implement Logger with Adapter', 'Group static bindings behind an explicitly imported module declaration. Include the composition in main before executable statements; its own file must import every referenced contract and implementation.'),
|
|
59
|
+
include: keyword('include Services', 'Expand an explicitly imported composition into the application root. Duplicate bindings and dependency cycles are checked after all includes are collected.'),
|
|
60
|
+
IndexError: type('IndexError implements Error', 'Checked failure for an invalid List.get position. Catch it, declare unless IndexError, or use List.at for a nullable lookup.'),
|
|
61
|
+
ArithmeticError: type('ArithmeticError implements Error', 'Checked failure for division by zero. int arithmetic otherwise wraps in the signed 64-bit range.'),
|
|
62
|
+
ConversionError: type('ConversionError implements Error', 'Checked failure when c_int(value=number) cannot fit the signed 32-bit C int range. Catch it or declare unless ConversionError.'),
|
|
63
|
+
c_int: type('c_int', 'Signed 32-bit C int. Convert explicitly with c_int(value=number), which raises ConversionError on overflow. It widens to int without loss. AugScript int maps to int64_t at the C boundary.'),
|
|
64
|
+
interceptor: keyword('interceptor Name<T>(resolve Dependency dependency) { around(...) returns T { ... } }', 'Declare a reusable wrapper for functions, methods, or class construction. Apply it with `[Name]` or `[Name(y=x)]`. Inputs match target labels automatically; explicit mappings rename them. Tags enter in written order and results unwind in reverse. Each layer creates a fresh instance; dependencies are forwarded from the target header. Effective contracts include every layer\u2019s changes, capabilities, errors, and dependencies. Generic types are inferred from the target. Interceptors follow normal imports, exports, and underscore privacy.'),
|
|
65
|
+
around: fn('around(Type input) returns Type { return next(); }', 'The required entry point of an interceptor. Its parameters select target arguments, and its result must fit the target return type. Omit `returns` for void. It may validate, override mapped arguments, inspect the result, throw a checked error, or return early. Declare generic parameters on the interceptor header. Helper methods can be declared alongside around.'),
|
|
66
|
+
next: fn('next(mappedLabel=value) returns TargetResult', 'Continue to the next interceptor layer or the original function/constructor. Available only inside an interceptor around body. `next()` forwards original arguments unchanged; optional labeled overrides use the interceptor parameter names and map back to the target. Unselected arguments are forwarded automatically. The compiler requires at most one next call on each execution path. Target errors propagate through the chain; additional errors declared by around become checked errors of the tagged callable.'),
|
|
67
|
+
import: keyword('import Logger and ConsoleLogger from logging', 'Bring public declarations into this file. Use `and` for several names, or `import everything from logging` for all public sibling declarations or folder exports. Imported dependencies are never re-exported implicitly. Names or modules starting with `_` stay private. A sibling module uses its filename without `.aug`; a folder exposes only names listed in `export.aug`.'),
|
|
68
|
+
and: keyword('left and right', 'Logical AND on bool values. Skip the right operand when the left operand is false. Also join named imports, checked errors, contracts, and grouped task waits. Comparisons and not bind before and; and binds before or.'),
|
|
69
|
+
or: keyword('left or right', 'Logical OR on bool values. Skip the right operand when the left operand is true. This is the lowest-precedence boolean operator. Symbolic || is rejected.'),
|
|
70
|
+
not: keyword('not count == 0', 'Negate a bool expression. Comparisons bind before not, so not count == 0 means not (count == 0). not binds before and and or. Use parentheses to negate only one comparison operand. Symbolic ! is rejected; != remains inequality.'),
|
|
71
|
+
everything: keyword('import everything from logging', 'Import every public declaration defined by a sibling file, or every public export listed in a folder’s export.aug. Private names and transitive imports are excluded. Name conflicts are compile errors. Explicit named imports make dependencies easier to understand.'),
|
|
72
|
+
test: keyword('test Calculator subject: ... or test add: ... or test endpoint getUser client: ...', 'Declare tests beside the class, function, or endpoint. Class suites initialize their subject; function suites omit a subject. Endpoint suites receive a native pipeline client. Parameterized it cases use for (inputs) in tuple rows. Tests are omitted from production executables; aug test selects groups/cases and --coverage records statement lines.'),
|
|
73
|
+
when: keyword('when GROUP_NAME { implement Dependency with Fake; ... }', 'Group related test cases and declare their test dependencies. Names may be identifiers or quoted descriptions. Put bindings first, then setup statements, then it cases. Each case re-runs setup with fresh bindings in a separate native process; production bindings and startup code do not run.'),
|
|
74
|
+
it: keyword('it TEST_NAME { assert(condition) }', 'Define a test case within a when group. Names may be identifiers or quoted descriptions. Group setup variables are visible, but other cases are not. Failed assertions and uncaught errors fail this case; the runner continues with the remaining cases. A case that executes no assertions fails.'),
|
|
75
|
+
pass: keyword('pass', 'An empty body. Use it inside an indented interface, class, function, or statement block. It performs no operation. Empty braced blocks may use {} instead.'),
|
|
76
|
+
in: keyword('interface Consumer<in T>', 'Declare a contravariant interface type parameter. It may occur only in checked input positions. User-defined types are otherwise invariant. The same word is used by for iteration.'),
|
|
77
|
+
out: keyword('interface Producer<out T>', 'Declare a covariant interface type parameter. It may occur only in checked output positions. Mutable containers are invariant; classes and interceptors cannot declare variance.'),
|
|
78
|
+
changes: keyword('increment() changes self', 'Declare observable mutation of self or a borrowed input. Callers must provide mutable access. Ordinary functions and methods are pure by default; changing a local variable or a fresh local object does not change caller-owned state.'),
|
|
79
|
+
uses: keyword('save(resolve FileWriter files, string path) uses files.write unless FileError', 'Declare the external capability operations this callable may use. Interfaces, public standalone functions, default methods and interceptor around methods keep explicit contracts. Class implementations and private helpers infer uses when omitted; hover, explain and API docs show the result. An explicit uses clause remains an upper bound. Effects are checked through calls and interceptor layers; implementations cannot exceed their interface contract. changes and unless remain explicit, and construction stays pure.'),
|
|
80
|
+
mutable: keyword('Counter(mutable int initial to _count)', 'Declare mutable class storage. Header fields are otherwise read-only after construction. An explicit public argument label can initialize private storage with Type label to _field. Mutating methods declare changes self and callers provide mutable access.'),
|
|
81
|
+
capability: keyword('capability Console { write(string value) uses Console.write }', 'Declare an interface for an external effect. Import the standard Console, FileReader, FileWriter and Arguments contracts from august.io, select adapters in main, and receive them through resolve parameters. Operations remain visible in uses clauses and can be replaced in tests.'),
|
|
82
|
+
from: keyword('import Name from module;', 'Names the source of an import or export. Dotted paths cross folders; each crossed folder must expose the next one with `export folder child;`. A module starting with `_` is private.'),
|
|
83
|
+
export: keyword('export Name from sibling;', 'Expose a public sibling declaration to other folders. Names, modules, and folders starting with `_` are private and cannot be exported. Export declarations belong only in `export.aug`.\n\n```aug\nexport Logger from logger;\n```'),
|
|
84
|
+
folder: keyword('export folder child;', 'Expose a public child folder through the current folder’s `export.aug`. A folder starting with `_` cannot be exported.'),
|
|
85
|
+
bind: keyword('Use implement Interface with Implementation', 'This old binding spelling is rejected. Use implement Interface with Implementation. The editor migration fix or aug migrate --write upgrades old source without changing its binding contract.'),
|
|
86
|
+
implement: keyword('implement Interface with Implementation', 'Register an implementation in main or test setup. Stateless bindings are shared by default; stateful bindings are fresh. Choose shared mutable or scoped mutable explicitly when retaining mutable state. Headers supply all construction dependencies; binding order is independent and cycles are checked.'),
|
|
87
|
+
with: keyword('implement key with Class;', 'Separates a binding key from its implementing class. The class must satisfy an interface key.'),
|
|
88
|
+
to: keyword('destination to value', 'Alternative to = in assignments, typed declarations, labeled call arguments and interceptor mappings. Type publicLabel to _storage separates a public constructor input from private storage. resolve app to program retrieves a binding using its declared lifetime. Configure assignment in main.yaml for consistent formatting.'),
|
|
89
|
+
resolve: keyword('resolve Logger logger; resolve app to program', 'Declare a dependency in a class or callable header. Callers omit its argument and forward the matching header dependency. Only main and test setup retrieve bindings directly with resolve app to program. Assignment-form resolve is rejected. Scoped dependencies require a scope block.'),
|
|
90
|
+
class: keyword('No class keyword', 'Class declarations start with their name and must include `implements`: `Worker() implements IWorker { ... }`. Members starting with `_` are private to the class; other members are public. A private header field still accepts its labeled constructor argument. Remove the old `class` prefix.'),
|
|
91
|
+
interface: keyword('interface Name extends Parent { ... }', 'Declare a contract. Interfaces may extend several interfaces and may provide default method bodies. A class must implement every method without a default. Method signatures start with their name, for example `log(string message);`.'),
|
|
92
|
+
implements: keyword('Name() implements Interface { ... }', 'Marks a declaration as a class and lists the interfaces it satisfies. Every class needs at least one interface. Method signatures must match. Conflicting default implementations require an override. Put constructor work in an initialize block inside the class.'),
|
|
93
|
+
extends: keyword('interface Child extends Parent, Other { ... }', 'Inherit methods from one or more interfaces. Class inheritance is not supported.'),
|
|
94
|
+
function: keyword('No function keyword', 'Functions and methods start with their name: `greet(string name) { ... }` or `greet(string name) returns string;`. Remove the old `function` prefix. Parameters use `Type name` order and callers use labels. Omit `returns` for a `void` result.'),
|
|
95
|
+
returns: keyword('name() returns Type', 'Specify a function or method return type. Without this clause, the result is `void`; the body may end without `return` or use `return;`. Returning a value requires a declared return type. `returns own Type` transfers ownership to the caller.'),
|
|
96
|
+
return: keyword('return expression;', 'Finish the current function or method and give its result to the caller. A `void` function can use `return;`.'),
|
|
97
|
+
unless: keyword('load(bool fail) returns string unless FileError', 'Declare checked failures a function may raise instead of returning its result. Callers must catch the failures or declare them with unless too. Separate several types with `and` or commas; `unless Error` accepts any error type. The statement that raises an error remains `throw`.'),
|
|
98
|
+
throws: keyword('Use unless', 'This old error-contract spelling is rejected. Replace `throws FileError` with `unless FileError`. Javadoc `@throws` remains supported.'),
|
|
99
|
+
throw: keyword('throw error;', 'Raise a value whose class implements `Error`. The enclosing function must declare the error or the call must be handled by a matching `catch`.'),
|
|
100
|
+
try: keyword('try { ... } catch Error error { ... }', 'Run statements that may throw checked errors. Add a `catch` for each error, or use `catch Error` for any throwable error.'),
|
|
101
|
+
catch: keyword('catch Error error { ... }', 'Handle a thrown error from the preceding `try` block. The caught value is available under the name after its type.'),
|
|
102
|
+
if: keyword('if condition: ...', 'Run a block when its condition is bool. Use braces or a trailing colon and an indented body. Tabs or spaces are accepted; mixed indentation prefixes are rejected.'),
|
|
103
|
+
else: keyword('else { ... }', 'Run this block when the preceding `if` condition is false.'),
|
|
104
|
+
while: keyword('while condition { ... }', 'Repeat a block while its condition remains `bool`.'),
|
|
105
|
+
own: keyword('own Type name to expression;', 'Give a value exclusive ownership and deterministic cleanup at scope exit. Owned values cannot be copied; they can move into `own` parameters, fields, or returns. `=` is also accepted.\n\n```aug\nown Resource resource to Resource();\n```'),
|
|
106
|
+
borrow: keyword('borrow value { ... }', 'Take exclusive mutable access for the duration of this block. Ordinary reads need no borrow. Managed List, Set, and Map mutations require one. Starting a child that reads the value suspends this mutation right until wait for the child.\n\n```aug\nborrow items { items.append(value=1) }\n```'),
|
|
107
|
+
unsafe: keyword('unsafe { ... }', 'Permit calls to declared `extern C` functions within this block. The compiler does not verify the safety of foreign code.'),
|
|
108
|
+
extern: keyword('extern C name(Type arg) returns Type', 'Declare a C function. Calls require unsafe and external callables declare uses C.name. int maps to int64_t, c_int to signed 32-bit int, float to double, bool to C bool, and string to a temporary UTF-8 const char pointer. Foreign code must respect the declared ABI and cannot retain managed pointers.'),
|
|
109
|
+
C: keyword('extern C name(...);', 'Selects C as the foreign function interface for an `extern` declaration.'),
|
|
110
|
+
true: keyword('true', 'Boolean true. Conditions and logical operators require `bool`.'),
|
|
111
|
+
false: keyword('false', 'Boolean false. and and or evaluate the right side only when needed. Conditions require bool values.'),
|
|
112
|
+
null: keyword('null', 'The absent value of optional Type. Omitted optional inputs also become null. Narrow local values with if value != null, an early return guard, or match null/some before calling members. Fields remain conservative because another alias may change their value.'),
|
|
113
|
+
int: type('int', 'Signed 64-bit integer, from -9223372036854775808 to 9223372036854775807. Literals retain their exact value. Addition, subtraction, multiplication and MIN/-1 division wrap modulo 2^64. Dynamic division requires ArithmeticError handling. Mixed float arithmetic may lose integer precision.'),
|
|
114
|
+
float: type('float', 'Floating point number type. Arithmetic supports `+`, `-`, `*`, and `/`.'),
|
|
115
|
+
bool: type('bool', 'Boolean type used by conditions and logical operators.'),
|
|
116
|
+
string: type('string', 'Immutable valid Unicode encoded as UTF-8, without embedded NUL. Invalid literals are compile errors and invalid text files raise FileError. The + operator joins strings. C string pointers live only for the unsafe call.'),
|
|
117
|
+
void: type('void', 'No return value. A function can omit `returns void`.'),
|
|
118
|
+
Error: type('Error', 'Root throwable interface. User defined error classes implement `Error`; `catch Error` handles any throwable type.'),
|
|
119
|
+
FileError: type('FileError', 'Built in checked error from text file operations. Catch it or declare `unless FileError`.'),
|
|
120
|
+
List: type('List<T>', 'Ordered collection: `[1, 2]` infers List<int>. A typed declaration supplies empty or nested literal types: `List<int> numbers = []`. `List<T>(...)` also accepts positional elements. `append(value=...)` requires mutable access; `get(index=...)` reads; `length()` returns its size.'),
|
|
121
|
+
Set: type('Set<T>', 'Hash set of unique values: `{1, 2, 1}` infers Set<int> with two items. Use `Set<int> numbers = {}` or `Set<int>()` for an empty set. `add(value=...)` requires mutable access; `contains(value=...)` and `length()` read. Primitive values and immutable tuples use value equality; other objects use identity.'),
|
|
122
|
+
Tuple: type('Tuple<T1, T2, ...>', 'Fixed immutable positions: `(1, 2)` infers Tuple<int, int>, `(1, "apple")` infers Tuple<int, string>. `(1)` is grouping, `(1,)` is a singleton tuple, and `()` is empty. `get(index=0)` requires a constant index so its result type is known. `length()` reads its size. Tuples compare by their items; contained objects remain managed references.'),
|
|
123
|
+
Map: type('Map<K,V>', 'Hash map: `{1: "apples", 2: "pears"}` infers Map<int, string>. A typed declaration supplies empty types: `Map<int, string> fruit = {}`. Duplicate keys keep the last value. `set(key=..., value=...)` requires mutable access; `get(key=...)` returns optional V; `contains(key=...)` and `length()` read. Primitive keys and tuples compare by value; other objects use identity.'),
|
|
124
|
+
assert: fn('assert(condition) returns void', 'Assert a bool inside a test or its group setup. `assert(condition=...)` also works. On failure, report the condition, file, and line; mark the case failed and raise an error. Catching that error cannot make the case pass. A case must execute at least one assertion.'),
|
|
125
|
+
print: fn('print(value=...) returns void', 'Write a value followed by a newline to standard output. The `value` label is required.'),
|
|
126
|
+
arguments: fn('arguments() returns List<string>', 'Read arguments after `--` when running a program: `aug run project -- first second`.'),
|
|
127
|
+
read_file: fn('read_file(path=string) returns string unless FileError', 'Read a UTF-8 text file. Catch `FileError` or declare it in the calling function.'),
|
|
128
|
+
write_file: fn('write_file(path=string, content=string) returns void unless FileError', 'Write UTF-8 text to a file. Catch `FileError` or declare it in the calling function.'),
|
|
129
|
+
'==': operator('left == right', 'Compare values for equality; the result is `bool`.'),
|
|
130
|
+
'!=': operator('left != right', 'Compare values for inequality; the result is `bool`.'),
|
|
131
|
+
'<': operator('left < right', 'Compare compatible numbers. Inside type arguments, `<` starts a generic argument list.'),
|
|
132
|
+
'<=': operator('left <= right', 'Compare compatible numbers; the result is `bool`.'),
|
|
133
|
+
'>': operator('left > right', 'Compare compatible numbers. Inside type arguments, `>` ends a generic argument list.'),
|
|
134
|
+
'>=': operator('left >= right', 'Compare compatible numbers; the result is `bool`.'),
|
|
135
|
+
'&&': operator('Use and', 'Symbolic boolean operators are rejected. Replace && with and; the right side is skipped when the left side is false.'),
|
|
136
|
+
'||': operator('Use or', 'Symbolic boolean operators are rejected. Replace || with or; the right side is skipped when the left side is true.'),
|
|
137
|
+
'!': operator('Use not', 'Symbolic boolean negation is rejected. The migration fix preserves grouping when replacing ! with not.'),
|
|
138
|
+
'+': operator('left + right', 'Add numbers or join strings.'),
|
|
139
|
+
'-': operator('left - right', 'Subtract numbers. Unary `-` negates a number.'),
|
|
140
|
+
'*': operator('left * right', 'Multiply numbers.'),
|
|
141
|
+
'/': operator('left / right', 'Divide numbers. Integer division truncates toward zero. A potentially zero divisor raises checked ArithmeticError; a literal nonzero divisor needs no error clause. MIN/-1 wraps to MIN.'),
|
|
142
|
+
'=': operator('name = value;', 'Assign a value. `to` is an equivalent assignment spelling: `name to value;` or `Type name to value;`. Use `own Type name to value;` for exclusive ownership.'),
|
|
143
|
+
'=>': operator('Use initialize', 'The arrow constructor spelling is rejected. Put initialize { ... } or its indented form inside the class or record. The editor migration fix moves the body and preserves behavior.'),
|
|
144
|
+
'?': operator('optional Type', 'Type? is rejected. Use optional Type for a value or null; omitted optional inputs and fields also become null. The migration fix upgrades the spelling.'),
|
|
145
|
+
'.': operator('receiver.member', 'Access a method or property. A member starting with `_` is private to its declaring type; other members are public. Mutable access still follows borrow rules.'),
|
|
146
|
+
';': operator('statement;', 'Optional statement separator. Newlines, a closing block brace, or end of file also terminate statements. Use semicolons to separate several statements on one line. Expressions continue inside parentheses and collection literals, or after an unfinished operator.'),
|
|
147
|
+
'{': operator('{1, 2} or {1: "apples"}', 'Start a set literal, map literal, or statement block. Comma-separated values create a Set; key: value pairs create a Map. Empty {} needs a declared Set or Map type. Classes, interfaces, interceptors, tests, functions, and control flow use braces for blocks.'),
|
|
148
|
+
'}': operator('{ ... }', 'End a block, set literal, or map literal.'),
|
|
149
|
+
'(': operator('(1, 2)', 'Start a tuple, grouped expression, call argument list, function parameters, or class header. A comma creates a tuple; a single expression without a comma is grouping.'),
|
|
150
|
+
')': operator('( ... )', 'End a tuple, grouped expression, argument list, parameter list, or class header.'),
|
|
151
|
+
',': operator('first, second', 'Separate parameters, arguments, type arguments, or interfaces.'),
|
|
152
|
+
':': operator('if condition: ... or {1: "apples"}', 'After a block header, introduce a body indented with tabs or spaces. Dedenting ends that body. Each block may independently use braces or indentation. In a map literal, separate a key from its value; collection and parenthesis continuation indentation has no block meaning.'),
|
|
153
|
+
'[': operator('[1, 2] or [Validator(y=x)]', 'Start a list literal, or an interceptor annotation immediately before a callable declaration. Lists infer one element type. Interceptor mappings connect processor labels to target labels; stacked annotations enter in written order.'),
|
|
154
|
+
']': operator('[ ... ]', 'End a list literal or interceptor annotation.'),
|
|
155
|
+
'->': operator('->', 'This token is reserved for future syntax and is not currently valid AugScript.'),
|
|
156
|
+
'@param': { category: 'tag', detail: '@param name description', documentation: 'Document a parameter in the Javadoc comment immediately before a class, function, or method. The text appears in hover and signature help.' },
|
|
157
|
+
'@return': { category: 'tag', detail: '@return description', documentation: 'Document the returned value of a function or method.' },
|
|
158
|
+
'@returns': { category: 'tag', detail: '@returns description', documentation: 'Alias of `@return`.' },
|
|
159
|
+
'@throws': { category: 'tag', detail: '@throws ErrorType description', documentation: 'Document a declared error and when it is raised.' },
|
|
160
|
+
'@exception': { category: 'tag', detail: '@exception ErrorType description', documentation: 'Alias of `@throws`.' },
|
|
161
|
+
'@deprecated': { category: 'tag', detail: '@deprecated reason', documentation: 'Explain why this declaration should no longer be used.' },
|
|
162
|
+
'@see': { category: 'tag', detail: '@see OtherSymbol', documentation: 'Point readers to related declarations or documentation.' },
|
|
163
|
+
'@code': { category: 'tag', detail: '{@code expression}', documentation: 'Show an inline fragment as code in generated editor help.' },
|
|
164
|
+
'@link': { category: 'tag', detail: '{@link Type}', documentation: 'Show a related declaration name as code in generated editor help.' },
|
|
165
|
+
'@inheritDoc': { category: 'tag', detail: '{@inheritDoc}', documentation: 'Insert documentation from the implemented or extended interface method.' },
|
|
166
|
+
};
|
|
167
|
+
for (const operation of builtinFunctions)
|
|
168
|
+
if (!['int', 'c_int'].includes(operation.name))
|
|
169
|
+
languageHelp[operation.name] = fn(`${operation.name}(${operation.parameters.map(param => `${param.label}=${param.type}`).join(', ')}) returns ${operation.returns}` +
|
|
170
|
+
(operation.errors?.length ? ` unless ${operation.errors.join(' and ')}` : ''), operation.documentation);
|
|
171
|
+
export const diagnosticHelp = {
|
|
172
|
+
SYNTAX: 'Use word boolean operators, initialize blocks, optional Type, implement with, and resolve Key to name. The editor migration fix or aug migrate --write upgrades rejected legacy spellings while preserving grouping.',
|
|
173
|
+
NATIVE: 'The native C toolchain reported an error at this AugScript source location. Check the external C declaration, linker configuration, and generated .aug-build/program.c; debug builds retain source line mapping.',
|
|
174
|
+
CONFIG: 'main.yaml uses the documented scalar settings and list settings. Duplicate keys, unsupported values, and unknown lint rules are errors during check.',
|
|
175
|
+
PACKAGE: 'Declare an import alias in main.yaml packages (or aug-package.json dependencies for a library), then run aug install. Commit aug.lock.json; use --frozen in CI. Imports cross only export.aug boundaries. Installed sources and compiler versions must match the lock; build/check never fetch packages.',
|
|
176
|
+
MODULE: 'Keep imports acyclic and follow main.yaml module_dependencies. strict_modules also requires sibling public imports to appear in export.aug.',
|
|
177
|
+
LINT: 'Optional project policies point out hidden dependencies, discarded errors, and growing public surfaces. Enable individual rules in main.yaml lint.',
|
|
178
|
+
DOC: 'Javadoc @param names use public input labels. @return requires a value-returning callable; @throws names an unless error. Enable public_docs for missing-documentation warnings.',
|
|
179
|
+
RECORD: 'Use deeply immutable data in record fields. Behavioral objects, mutable collections, resolve dependencies, and ownership belong in classes with explicit interfaces.',
|
|
180
|
+
MATCH: 'Cover true/false, null/some, or add else. Each pattern must be compatible with the value, and cases must remain reachable.',
|
|
181
|
+
PATTERN: 'Tuple patterns need exactly the same number of positions and introduce new names in the current scope.',
|
|
182
|
+
ITERATION: 'for traverses a List, Set, Map, or homogeneous Tuple. Use tuple destructuring for map entries and heterogeneous tuples.',
|
|
183
|
+
NUMBER: 'int is signed 64-bit with defined wrapping arithmetic. Integer literal spelling is exact. Float literals must be finite.',
|
|
184
|
+
TEXT: 'Strings contain valid Unicode encoded as UTF-8, without NUL. Binary data needs an explicit unsafe adapter.',
|
|
185
|
+
EFFECT: 'Public function and interface contracts explicitly declare uses capability.operation. Implementations and private helpers infer omitted uses, while explicit clauses remain upper bounds. Declare changes for mutation and unless for errors. Receive dependencies in resolve header parameters; constructors and cleanup remain pure. Inferred effects cannot exceed an implemented interface or hold a lock during I/O.',
|
|
186
|
+
MUTABILITY: 'Class storage is read-only after construction unless marked mutable. Managed function inputs grant reading; use a borrow parameter and a changes contract to mutate them. Public read-only fields do not grant mutable access through aliases.',
|
|
187
|
+
GENERIC: 'Type arguments must be concrete at a call and consistent across labeled inputs. Mutable and user-defined types are invariant by default. Supply explicit type arguments when inputs do not determine them.',
|
|
188
|
+
INDENT: 'Put the body after a trailing colon on the next line. Indent beyond its header, keep each block level consistent, and use tabs or spaces without mixing them in a prefix. Dedent to an enclosing level; use pass for an empty body.',
|
|
189
|
+
COLLECTION: 'Use compatible item types or a declared collection type. Empty [] and {} need a contextual type. A tuple may contain different types; tuple.get needs a constant index.',
|
|
190
|
+
TEST: 'Place the suite beside its declaration. Class tests initialize their named subject; test endpoint NAME client supplies an HTTP pipeline client. Put when bindings and setup before it cases and assert a bool in every case. Run aug test --group NAME to select a group.',
|
|
191
|
+
HTTP: 'Declare endpoint inputs with from path/query/header/body/cookie/form/request and dependencies with resolve. Select endpoints in main with serve. HTTP policies use literal options and explicit capability mappings; put them before custom parameter interceptors.',
|
|
192
|
+
JSON: 'Expose concrete immutable data records and collections. Decode<T>() requires a concrete JSON data type; freeze existing mutable collection aliases before storing them in a record.',
|
|
193
|
+
CONCURRENCY: 'Use scope for child-task lifetimes, start a labeled call, and wait for its result before mutating or moving any object the child captured. This includes writes inside an existing borrow block. A start inside a loop can create several children; use a scope inside the loop to join each iteration. Use Shared<T> and a short lock block for shared mutation; release the lock before I/O, waits, or starting tasks.',
|
|
194
|
+
INTERCEPTOR: 'Declare an interceptor with one around body. Map its selected inputs to target labels, preserve the target result and ownership, and supply constructor dependencies through resolve.',
|
|
195
|
+
NEXT: 'Use next only inside around, with optional labeled overrides. Each execution path may call it at most once; loops and catch paths can repeat a call.',
|
|
196
|
+
LEX: 'Check quotes, comment terminators, and supported characters.',
|
|
197
|
+
PARSE: 'Check braces, statement boundaries, declaration order, and Type name parameters. Semicolons are optional. Use unless for checked error contracts.',
|
|
198
|
+
CALL: 'Use a label for each ordinary argument, such as `Greeter(x=4)`. Omit parameters marked `resolve`.',
|
|
199
|
+
PROJECT: 'Create `main.aug` at the project root; it is the entry point.',
|
|
200
|
+
MAIN: 'Keep bindings and executable statements in `main.aug`; put declarations in other `.aug` files.',
|
|
201
|
+
EXPORT: 'Only `export` statements belong in `export.aug`. Export declarations name a sibling file.',
|
|
202
|
+
IMPORT: 'Import a sibling file directly or an exposed name from a folder’s `export.aug`.',
|
|
203
|
+
NAME: 'A name must be declared in this file or explicitly imported before use.',
|
|
204
|
+
TYPE: 'Check the types in the expression, parameters, return value, and generic arguments.',
|
|
205
|
+
INTERFACE: 'Every class declares at least one interface with `implements`. Implement its required methods with exact signatures, or use defaults.',
|
|
206
|
+
DI: 'Declare implement key with Class in main.aug before executable statements, or in a test when group before setup. Each key has one target class.',
|
|
207
|
+
OWN: 'An `own` value has one owner; move it into another `own` location or use ordinary managed storage.',
|
|
208
|
+
BORROW: 'Use `borrow value { ... }` around a mutation of a process managed value.',
|
|
209
|
+
THROWS: 'Catch the checked error with `try/catch` or declare it on the enclosing function.',
|
|
210
|
+
PRIVATE: 'A name starting with `_` is private to its file or declaring type. Private names, modules, and folders cannot be imported or exported.',
|
|
211
|
+
FFI: 'Declare C functions with `extern C name(...);` and call them inside `unsafe { ... }`.',
|
|
212
|
+
};
|
package/src/html.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Server HTML accepts standard, inert elements; executable content uses endpoint actions. */
|
|
2
|
+
export const htmlTags = new Set('html head title meta link body main header footer nav section article aside div span p h1 h2 h3 h4 h5 h6 a ul ol li dl dt dd table caption thead tbody tfoot tr th td form label input button select option optgroup textarea fieldset legend output progress meter img picture source video audio track figure figcaption details summary dialog pre code blockquote strong em b i u s small mark time br hr wbr area col embed param'.split(' '));
|
|
3
|
+
export const htmlVoidTags = new Set('area br col embed hr img input link meta param source track wbr'.split(' '));
|
|
4
|
+
export const htmlBooleanAttributes = new Set('disabled checked selected multiple required readonly autofocus hidden open controls loop muted autoplay novalidate formnovalidate reversed'.split(' '));
|
|
5
|
+
export const htmlUrlAttributes = new Set(['href', 'src', 'action', 'formaction', 'poster']);
|
|
6
|
+
const globals = new Set('id class className title lang dir role tabindex tabIndex style slot translate accesskey contenteditable draggable spellcheck'.split(' '));
|
|
7
|
+
const attributes = {
|
|
8
|
+
html: 'xmlns', meta: 'name content charset http-equiv', link: 'rel href type media sizes crossorigin integrity',
|
|
9
|
+
a: 'href target rel download hreflang type', form: 'action method enctype autocomplete target name novalidate',
|
|
10
|
+
input: 'name type value placeholder required disabled checked readonly min max step minlength maxlength pattern autocomplete autofocus multiple accept form',
|
|
11
|
+
button: 'name type value disabled form formaction formmethod formnovalidate', label: 'for htmlFor form',
|
|
12
|
+
textarea: 'name placeholder rows cols required disabled readonly minlength maxlength autocomplete',
|
|
13
|
+
select: 'name required disabled multiple size form', option: 'value selected disabled label', optgroup: 'label disabled', fieldset: 'name disabled form',
|
|
14
|
+
img: 'src alt width height loading decoding crossorigin srcset sizes', source: 'src type srcset sizes media',
|
|
15
|
+
audio: 'src controls autoplay loop muted preload', video: 'src controls autoplay loop muted preload poster width height', track: 'src kind label srclang default',
|
|
16
|
+
th: 'colspan rowspan scope headers', td: 'colspan rowspan headers', ol: 'start reversed type', li: 'value',
|
|
17
|
+
progress: 'value max', meter: 'value min max low high optimum', details: 'open name', dialog: 'open', time: 'datetime', output: 'for name form',
|
|
18
|
+
};
|
|
19
|
+
export function htmlAttribute(tag, name) {
|
|
20
|
+
if (tag === 'form' && name === 'onSubmit' || tag === 'button' && name === 'onClick')
|
|
21
|
+
return 'HttpAction';
|
|
22
|
+
if (name.startsWith('data-') || name.startsWith('aria-'))
|
|
23
|
+
return 'string';
|
|
24
|
+
if (globals.has(name) || attributes[tag]?.split(' ').includes(name))
|
|
25
|
+
return htmlBooleanAttributes.has(name) ? 'bool' : 'string';
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export const httpPolicyNames = ['RequireLogin', 'RequirePermission', 'LogRequest', 'RateLimit', 'Timeout', 'Cors', 'Compress'];
|
|
2
|
+
export function httpPolicyNativeName(name) {
|
|
3
|
+
return 'AUG_HTTP_POLICY_' + name.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
|
|
4
|
+
}
|
|
5
|
+
export const httpPolicyOptions = {
|
|
6
|
+
RequireLogin: { authentication: 'dependency:Authentication.authenticate' },
|
|
7
|
+
RequirePermission: { authentication: 'dependency:Authentication.authenticate', authorization: 'dependency:Authorization.authorize', permission: 'string' },
|
|
8
|
+
LogRequest: { logger: 'dependency:RequestLogger.complete' },
|
|
9
|
+
RateLimit: { requests: 'int', seconds: 'int' }, Timeout: { milliseconds: 'int' },
|
|
10
|
+
Cors: { origins: 'strings', headers: 'optional strings', credentials: 'optional bool' }, Compress: {},
|
|
11
|
+
};
|
|
12
|
+
export const httpPolicyOptionHelp = {
|
|
13
|
+
authentication: 'Map an explicit resolve Authentication input. Declare uses input.authenticate. Missing identity returns 401 before wire decoding.',
|
|
14
|
+
authorization: 'Map an explicit resolve Authorization input. Declare uses input.authorize. Denied permission returns 403.',
|
|
15
|
+
permission: 'Literal nonempty permission checked by the authorization adapter.',
|
|
16
|
+
logger: 'Map an explicit resolve RequestLogger input. Declare uses input.complete. The logger runs after completion or disconnect; put LogRequest first to observe rejected requests.',
|
|
17
|
+
requests: 'Literal request count per trusted transport peer and endpoint, from 1 to 1000000. Excess returns 429.',
|
|
18
|
+
seconds: 'Literal fixed-window duration, from 1 to 86400 seconds.',
|
|
19
|
+
milliseconds: 'Literal deadline from 1 to 3600000 milliseconds, covering handler, child tasks and response transport. Before output it returns 504; after output it closes the stream.',
|
|
20
|
+
origins: 'Literal list of exact HTTP(S) origins. "*" is allowed only without credentials. A disallowed supplied Origin returns 403.',
|
|
21
|
+
headers: 'Optional literal list of permitted CORS request header names. Preflight checks every requested header.',
|
|
22
|
+
credentials: 'Optional literal boolean enabling credentialed CORS. Default false; wildcard origins cannot enable it.',
|
|
23
|
+
};
|
|
24
|
+
/** Policy configuration is literal; service dependencies are explicit endpoint inputs. */
|
|
25
|
+
export function checkHttpPolicy(annotation, fn, diagnostics, canonical) {
|
|
26
|
+
const name = annotation.name, options = {}, dependencies = [];
|
|
27
|
+
const report = (message) => diagnostics.push({ ...annotation.span, code: 'HTTP', message });
|
|
28
|
+
const specs = httpPolicyOptions;
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
for (const entry of annotation.mappings) {
|
|
31
|
+
if (seen.has(entry.name)) {
|
|
32
|
+
report(`Duplicate ${name} option ${entry.name}`);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
seen.add(entry.name);
|
|
36
|
+
const spec = specs[name][entry.name];
|
|
37
|
+
if (!spec) {
|
|
38
|
+
report(`${name} has no option ${entry.name}`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (spec.startsWith('dependency:')) {
|
|
42
|
+
const [type, operation] = spec.slice(11).split('.'), index = fn.params.findIndex(param => param.name === entry.source);
|
|
43
|
+
const param = fn.params[index];
|
|
44
|
+
if (entry.value || !param?.injected || param.type.name !== type || param.type.nullable || param.type.optional)
|
|
45
|
+
report(`${name}.${entry.name} maps an explicit resolve ${type} endpoint parameter`);
|
|
46
|
+
else if (!canonical(param, type))
|
|
47
|
+
report(`${name}.${entry.name} requires the august.web ${type} capability`);
|
|
48
|
+
else {
|
|
49
|
+
dependencies[Object.keys(specs[name]).filter(key => specs[name][key].startsWith('dependency:')).indexOf(entry.name)] = index;
|
|
50
|
+
if (!fn.uses?.some(effect => effect.source === param.name && effect.operation === operation))
|
|
51
|
+
report(`Declare uses ${param.name}.${operation} for ${name}`);
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const value = entry.value, wanted = spec.replace(/^optional /, '');
|
|
56
|
+
const literal = (value) => value?.kind === 'literal';
|
|
57
|
+
if (wanted === 'strings' && value?.kind === 'collection' && value.collection === 'List' && value.items.every(item => literal(item) && typeof item.value === 'string'))
|
|
58
|
+
options[entry.name] = value.items.map(item => item.value);
|
|
59
|
+
else if (literal(value) && (wanted === 'string' && typeof value.value === 'string' || wanted === 'bool' && typeof value.value === 'boolean' || wanted === 'int' && typeof value.value === 'number' && value.numericType !== 'float' && Number.isSafeInteger(value.value)))
|
|
60
|
+
options[entry.name] = value.value;
|
|
61
|
+
else
|
|
62
|
+
report(`${name}.${entry.name} requires a literal ${wanted}`);
|
|
63
|
+
}
|
|
64
|
+
for (const [option, spec] of Object.entries(specs[name]))
|
|
65
|
+
if (!spec.startsWith('optional ') && !seen.has(option))
|
|
66
|
+
report(`${name} requires ${option}`);
|
|
67
|
+
if (annotation.typeArgs.length)
|
|
68
|
+
report(`${name} does not take type arguments`);
|
|
69
|
+
if (name === 'RateLimit' && (!Number.isInteger(options.requests) || Number(options.requests) < 1 || Number(options.requests) > 1000000 || !Number.isInteger(options.seconds) || Number(options.seconds) < 1 || Number(options.seconds) > 86400))
|
|
70
|
+
report('RateLimit requests must be 1..1000000 and seconds 1..86400');
|
|
71
|
+
if (name === 'Timeout' && (!Number.isInteger(options.milliseconds) || Number(options.milliseconds) < 1 || Number(options.milliseconds) > 3600000))
|
|
72
|
+
report('Timeout milliseconds must be 1..3600000');
|
|
73
|
+
if (name === 'RequirePermission' && (!options.permission || /[\x00-\x1f]/.test(String(options.permission))))
|
|
74
|
+
report('RequirePermission needs a nonempty permission without controls');
|
|
75
|
+
if (name === 'Cors') {
|
|
76
|
+
const origins = options.origins;
|
|
77
|
+
if (!origins?.length || origins.some(origin => { if (origin === '*')
|
|
78
|
+
return !!options.credentials; try {
|
|
79
|
+
const url = new URL(origin);
|
|
80
|
+
return !['https:', 'http:'].includes(url.protocol) || url.origin !== origin;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return true;
|
|
84
|
+
} }))
|
|
85
|
+
report('Cors origins are exact HTTP(S) origins; wildcard cannot use credentials');
|
|
86
|
+
if (options.headers?.some(header => !/^[!#$%&'*+.^_`|~0-9a-z-]+$/i.test(header)))
|
|
87
|
+
report('Cors headers contain HTTP field names');
|
|
88
|
+
}
|
|
89
|
+
return { name, annotation, options, dependencies };
|
|
90
|
+
}
|
package/src/inference.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { sameType, tyName } from "./types.js";
|
|
2
|
+
/** One unification operation for callable and interceptor type arguments. */
|
|
3
|
+
export function inferType(ref, actual, names, types, conflict, view = (_, actual) => actual) {
|
|
4
|
+
if (names.includes(ref.name) && !ref.args.length) {
|
|
5
|
+
const candidate = ref.nullable ? { ...actual, nullable: false, optional: false } : actual;
|
|
6
|
+
const previous = types.get(ref.name);
|
|
7
|
+
if (!previous)
|
|
8
|
+
types.set(ref.name, candidate);
|
|
9
|
+
else if (!sameType(previous, candidate))
|
|
10
|
+
conflict(`Conflicting inference for ${ref.name}: ${tyName(previous)} and ${tyName(candidate)}; supply compatible values or explicit type arguments`);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const resolved = view(ref.name, actual);
|
|
14
|
+
if (resolved && ref.name === resolved.name && ref.args.length === resolved.args.length)
|
|
15
|
+
ref.args.forEach((arg, index) => inferType(arg, resolved.args[index], names, types, conflict, view));
|
|
16
|
+
}
|