@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/policies.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { basename, dirname, join, relative } from 'node:path';
|
|
2
|
+
import { orderGraph } from "./di.js";
|
|
3
|
+
import { javadocBefore } from "./javadoc.js";
|
|
4
|
+
import { callableDocumentation } from "./documentation.js";
|
|
5
|
+
export function projectPolicies(project) {
|
|
6
|
+
const diagnostics = [];
|
|
7
|
+
const enabled = (name) => project.config.lint.includes(name);
|
|
8
|
+
const report = (span, message, code, warning = false) => diagnostics.push({
|
|
9
|
+
file: span.file, line: span.line, column: span.column, message, code, severity: warning ? 'warning' : 'error'
|
|
10
|
+
});
|
|
11
|
+
const modules = new Map();
|
|
12
|
+
const module = (path) => relative(project.sourceRoot, dirname(path)).replaceAll('\\', '/') || '.';
|
|
13
|
+
const rules = project.config.module_dependencies.map(rule => {
|
|
14
|
+
const [owner, targets] = rule.split(':');
|
|
15
|
+
return { owner: owner.trim(), targets: targets.split(',').map(target => target.trim()).filter(Boolean) };
|
|
16
|
+
});
|
|
17
|
+
const matches = (pattern, value) => pattern === '*' || pattern.endsWith('/*') ?
|
|
18
|
+
pattern === '*' || value === pattern.slice(0, -2) || value.startsWith(pattern.slice(0, -1)) : pattern === value;
|
|
19
|
+
for (const file of project.files.values()) {
|
|
20
|
+
if (file.builtin || basename(file.path) === 'export.aug')
|
|
21
|
+
continue;
|
|
22
|
+
const edges = new Set();
|
|
23
|
+
for (const item of file.items)
|
|
24
|
+
if (item.kind === 'import') {
|
|
25
|
+
const imports = project.imports.get(item) ?? [];
|
|
26
|
+
for (const def of imports) {
|
|
27
|
+
if (def.file !== file.path && !project.files.get(def.file)?.builtin)
|
|
28
|
+
edges.add(def.file);
|
|
29
|
+
const from = module(file.path), to = project.files.get(def.file)?.package ? item.from.join('/') : module(def.file);
|
|
30
|
+
const rule = rules.find(rule => matches(rule.owner, from));
|
|
31
|
+
if (!file.package && rule && from !== to && !project.files.get(def.file)?.builtin && !rule.targets.some(target => matches(target, to)))
|
|
32
|
+
report(item.span, `${from} may not depend on ${to}; allowed: ${rule.targets.join(', ') || 'none'}`, 'MODULE');
|
|
33
|
+
if (!file.package && project.config.strict_modules && dirname(def.file) === dirname(file.path)) {
|
|
34
|
+
const surface = project.files.get(join(dirname(def.file), 'export.aug'));
|
|
35
|
+
if (!surface?.items.some(entry => entry.kind === 'export' && entry.name === def.name && entry.from === basename(def.file, '.aug')))
|
|
36
|
+
report(item.span, `Strict modules require ${def.name} from ${basename(def.file)} to appear in this folder's export.aug`, 'MODULE');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!file.package && item.everything && enabled('wildcard_imports'))
|
|
40
|
+
report(item.span, 'Expand everything to explicit named imports to keep dependencies visible', 'LINT', true);
|
|
41
|
+
}
|
|
42
|
+
modules.set(file.path, { key: file.path, dependencies: [...edges], span: file.items[0]?.span ?? { file: file.path, start: 0, end: 0, line: 1, column: 1 } });
|
|
43
|
+
if (file.package)
|
|
44
|
+
continue;
|
|
45
|
+
const publicNodes = file.items.filter(item => ['class', 'interface', 'interceptor', 'function', 'composition'].includes(item.kind) && 'name' in item && !item.name.startsWith('_'));
|
|
46
|
+
if (enabled('architecture') && edges.size > project.config.max_dependencies)
|
|
47
|
+
report(modules.get(file.path).span, `${basename(file.path)} depends on ${edges.size} files; consider a smaller module contract`, 'LINT', true);
|
|
48
|
+
const publicMembers = publicNodes.reduce((count, node) => count + 1 + ('methods' in node ? node.methods.filter(method => !method.name.startsWith('_')).length : 0) +
|
|
49
|
+
('fields' in node ? node.fields.filter(field => !field.name.startsWith('_')).length : 0), 0);
|
|
50
|
+
if (enabled('public_helpers') && publicMembers > project.config.max_public_symbols)
|
|
51
|
+
report(modules.get(file.path).span, `${publicMembers} public declarations and members; prefix implementation helpers with _ or expose a smaller folder surface`, 'LINT', true);
|
|
52
|
+
if (enabled('public_helpers'))
|
|
53
|
+
for (const node of publicNodes)
|
|
54
|
+
if (node.kind === 'function') {
|
|
55
|
+
const def = project.scopes.get(file.path)?.get(node.name);
|
|
56
|
+
const imported = [...project.imports.values()].some(imports => imports.some(imported => imported.id === def?.id));
|
|
57
|
+
const exported = project.files.get(join(dirname(file.path), 'export.aug'))?.items.some(item => item.kind === 'export' && item.name === node.name && item.from === basename(file.path, '.aug'));
|
|
58
|
+
const others = file.items.filter(item => item !== node);
|
|
59
|
+
const called = (value) => !!value && typeof value === 'object' && (Array.isArray(value) ? value.some(called) :
|
|
60
|
+
value.kind === 'name' && value.name === node.name ||
|
|
61
|
+
Object.entries(value).some(([key, child]) => key !== 'span' && called(child)));
|
|
62
|
+
if (!imported && !exported && called(others))
|
|
63
|
+
report(node.span, `${node.name} is only used within this file; prefix an implementation helper with _`, 'LINT', true);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
orderGraph([...modules.values()], (node, path) => report(node.span, `Import cycle: ${path.map(path => relative(project.root, path)).join(' -> ')}`, 'MODULE'));
|
|
67
|
+
for (const def of project.definitions.values()) {
|
|
68
|
+
if (project.files.get(def.file)?.builtin)
|
|
69
|
+
continue;
|
|
70
|
+
const source = project.files.get(def.file).source;
|
|
71
|
+
const declarations = [def.node, ...('methods' in def.node ? def.node.methods : [])];
|
|
72
|
+
for (const node of declarations) {
|
|
73
|
+
const doc = javadocBefore(source, 'annotations' in node && node.annotations?.length ? node.annotations[0].span.start : node.span.start);
|
|
74
|
+
const effectiveDoc = node.kind === 'function' ? callableDocumentation(project, node, def) : doc;
|
|
75
|
+
const own = !project.files.get(def.file)?.package;
|
|
76
|
+
const publicNode = !def.name.startsWith('_') && !node.name.startsWith('_');
|
|
77
|
+
const required = own && (project.config.spec.require_comments === 'all' || project.config.spec.require_comments === 'public' && publicNode);
|
|
78
|
+
if (required && !effectiveDoc)
|
|
79
|
+
report(node.span, `Document ${node.name} with Javadoc; main.yaml spec.require_comments is ${project.config.spec.require_comments}`, 'DOC');
|
|
80
|
+
else if (own && publicNode && enabled('public_docs') && !effectiveDoc)
|
|
81
|
+
report(node.span, `Document public ${node.name}'s contract with Javadoc`, 'DOC', true);
|
|
82
|
+
if (doc) {
|
|
83
|
+
const params = 'params' in node ? node.params : 'fields' in node ? node.fields : [];
|
|
84
|
+
for (const label of doc.parameters.keys())
|
|
85
|
+
if (!params.some(param => (param.label ?? param.name) === label))
|
|
86
|
+
report(node.span, `@param ${label} does not name a public input of ${node.name}`, 'DOC');
|
|
87
|
+
for (const tag of doc.tags ?? []) {
|
|
88
|
+
if (['return', 'returns'].includes(tag.name) && !('returns' in node && node.returns.name !== 'void'))
|
|
89
|
+
report(node.span, `@${tag.name} requires a value-returning callable`, 'DOC');
|
|
90
|
+
if (['throws', 'exception'].includes(tag.name)) {
|
|
91
|
+
const name = tag.value.split(/\s/)[0];
|
|
92
|
+
const errors = 'throws' in node ? node.throws : 'validationErrors' in node ? node.validationErrors ?? [] : [];
|
|
93
|
+
if (!('annotations' in node && node.annotations?.length) && !errors.some(error => error.name === name))
|
|
94
|
+
report(node.span, `@${tag.name} ${name} is absent from ${node.name}'s unless contract`, 'DOC');
|
|
95
|
+
}
|
|
96
|
+
if (!['param', 'return', 'returns', 'throws', 'exception', 'deprecated', 'see'].includes(tag.name))
|
|
97
|
+
report(node.span, `Unknown documentation tag @${tag.name}`, 'DOC');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!project.files.get(def.file)?.package && 'throws' in node && enabled('broad_errors') && node.throws.some(error => error.name === 'Error'))
|
|
101
|
+
report(node.span, `Prefer specific public errors on ${node.name}; unless Error hides recoverable cases`, 'LINT', true);
|
|
102
|
+
const visit = (body) => {
|
|
103
|
+
for (const stmt of body) {
|
|
104
|
+
if (stmt.kind === 'try')
|
|
105
|
+
for (const clause of stmt.catches) {
|
|
106
|
+
const mentions = (value) => !!value && typeof value === 'object' && (Array.isArray(value) ? value.some(mentions) :
|
|
107
|
+
value.kind === 'name' && value.name === clause.name ||
|
|
108
|
+
Object.entries(value).some(([key, child]) => key !== 'span' && mentions(child)));
|
|
109
|
+
if (enabled('discarded_errors') && !mentions(clause.body))
|
|
110
|
+
report(clause.span, `Caught ${clause.name} is discarded; record or deliberately recover from the failure`, 'LINT', true);
|
|
111
|
+
visit(clause.body);
|
|
112
|
+
}
|
|
113
|
+
if ('body' in stmt)
|
|
114
|
+
visit(stmt.body);
|
|
115
|
+
if (stmt.kind === 'if') {
|
|
116
|
+
visit(stmt.then);
|
|
117
|
+
visit(stmt.otherwise);
|
|
118
|
+
}
|
|
119
|
+
if (stmt.kind === 'match')
|
|
120
|
+
stmt.cases.forEach(clause => visit(clause.body));
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
if ('body' in node)
|
|
124
|
+
visit(node.body ?? []);
|
|
125
|
+
if ('constructorBody' in node)
|
|
126
|
+
visit(node.constructorBody ?? []);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return diagnostics;
|
|
130
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, join, resolve } from 'node:path';
|
|
3
|
+
/** Create a small, runnable application without replacing existing files. */
|
|
4
|
+
export function initProject(destination) {
|
|
5
|
+
const root = resolve(destination);
|
|
6
|
+
if (existsSync(root) && readdirSync(root).length)
|
|
7
|
+
throw new Error(`Directory is not empty: ${root}`);
|
|
8
|
+
const name = basename(root);
|
|
9
|
+
mkdirSync(root, { recursive: true });
|
|
10
|
+
const files = {
|
|
11
|
+
'main.aug': `import Greeter and SimpleGreeter from greeting\n\nimplement Greeter with SimpleGreeter\nresolve Greeter to greeter\nprint(value=greeter.greet(name="August"))\n`,
|
|
12
|
+
'greeting.aug': `/** Build a greeting for a named person. */\ninterface Greeter:\n /** Return a greeting for the named person. */\n greet(string name) returns string\n\n/** A plain-language greeting. */\nSimpleGreeter() implements Greeter:\n greet(string name) returns string:\n return "Hello, " + name + "!"\n\ntest SimpleGreeter greeter:\n when greetings:\n greeter = SimpleGreeter()\n it greets_a_person:\n assert(greeter.greet(name="August") == "Hello, August!")\n`,
|
|
13
|
+
'.gitignore': '.aug-build/\n.aug-spec/\n*.aug.md\n',
|
|
14
|
+
'README.md': `# ${name}\n\nThis is an August application. Start in \`main.aug\`; its dependencies and startup are visible there.\n\n\`greeting.aug\` contains a public interface, its implementation, and a same-file test.\n\n\`\`\`sh\naug check .\naug test .\naug spec .\naug run .\n\`\`\`\n\nFor the language guide, see https://GreenPandaStudios.github.io/augscript/getting-started.\n`,
|
|
15
|
+
};
|
|
16
|
+
for (const [file, contents] of Object.entries(files))
|
|
17
|
+
writeFileSync(join(root, file), contents, { flag: 'wx' });
|
|
18
|
+
return root;
|
|
19
|
+
}
|
package/src/project.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
import { parse } from "./parser.js";
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
5
|
+
import { projectPolicies } from "./policies.js";
|
|
6
|
+
import { builtinFunctions, builtinTypes } from "./builtins.js";
|
|
7
|
+
import { libraryChild, libraryRelative, standardLibraries } from "./libraries.js";
|
|
8
|
+
import { projectPackages, readPackage, sourcePaths } from "./package-manager.js";
|
|
9
|
+
export function isPrivateName(name) { return name.startsWith('_'); }
|
|
10
|
+
function diagnostic(file, line, column, message, code) {
|
|
11
|
+
return { file, line, column, message, code };
|
|
12
|
+
}
|
|
13
|
+
function sourceFiles(root) {
|
|
14
|
+
const output = [];
|
|
15
|
+
function walk(dir) {
|
|
16
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
17
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist')
|
|
18
|
+
continue;
|
|
19
|
+
const path = join(dir, entry.name);
|
|
20
|
+
if (entry.isDirectory())
|
|
21
|
+
walk(path);
|
|
22
|
+
else if (entry.isFile() && entry.name.endsWith('.aug'))
|
|
23
|
+
output.push(path);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
walk(root);
|
|
27
|
+
return output.sort();
|
|
28
|
+
}
|
|
29
|
+
export function loadProject(projectRoot, overrides = new Map(), cache) {
|
|
30
|
+
const root = resolve(projectRoot);
|
|
31
|
+
const files = new Map();
|
|
32
|
+
const definitions = new Map();
|
|
33
|
+
const scopes = new Map();
|
|
34
|
+
const imports = new Map();
|
|
35
|
+
const { config, diagnostics } = loadConfig(root);
|
|
36
|
+
let library;
|
|
37
|
+
let sourceRoot = root;
|
|
38
|
+
if (existsSync(join(root, 'aug-package.json'))) {
|
|
39
|
+
try {
|
|
40
|
+
const loaded = readPackage(root);
|
|
41
|
+
library = loaded.manifest;
|
|
42
|
+
sourceRoot = loaded.sourceRoot;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
diagnostics.push(diagnostic(join(root, 'aug-package.json'), 1, 1, error.message, 'PACKAGE'));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const packages = projectPackages(root, library?.dependencies ?? config.packages, sourceRoot);
|
|
49
|
+
diagnostics.push(...packages.diagnostics);
|
|
50
|
+
const read = (path) => {
|
|
51
|
+
const source = overrides.get(path) ?? readFileSync(path, 'utf8');
|
|
52
|
+
const cached = cache?.get(path);
|
|
53
|
+
if (cached?.file.source === source)
|
|
54
|
+
return cached;
|
|
55
|
+
const parsed = parse(path, source);
|
|
56
|
+
cache?.set(path, parsed);
|
|
57
|
+
return parsed;
|
|
58
|
+
};
|
|
59
|
+
for (const path of new Set([...sourceFiles(sourceRoot), ...overrides.keys()].filter(path => path.endsWith('.aug')))) {
|
|
60
|
+
const parsed = read(path);
|
|
61
|
+
files.set(path, parsed.file);
|
|
62
|
+
diagnostics.push(...parsed.diagnostics);
|
|
63
|
+
}
|
|
64
|
+
for (const scope of new Set(packages.scopes.values()))
|
|
65
|
+
for (const path of sourcePaths(scope.sourceRoot)) {
|
|
66
|
+
const parsed = read(path);
|
|
67
|
+
// Cached parse objects can be shared across project revisions.
|
|
68
|
+
files.set(path, { ...parsed.file, package: scope.path });
|
|
69
|
+
diagnostics.push(...parsed.diagnostics);
|
|
70
|
+
}
|
|
71
|
+
const libraries = standardLibraries();
|
|
72
|
+
const stdlibRoot = libraries.root;
|
|
73
|
+
const libraryFiles = new Set([stdlibRoot, ...libraries.modules.values()].flatMap(sourceFiles));
|
|
74
|
+
for (const path of libraryFiles) {
|
|
75
|
+
const parsed = read(path);
|
|
76
|
+
parsed.file.builtin = true;
|
|
77
|
+
files.set(path, parsed.file);
|
|
78
|
+
diagnostics.push(...parsed.diagnostics);
|
|
79
|
+
}
|
|
80
|
+
const main = files.get(join(root, 'main.aug'));
|
|
81
|
+
if (!main && !library)
|
|
82
|
+
diagnostics.push(diagnostic(join(root, 'main.aug'), 1, 1, 'Project requires main.aug at its root', 'PROJECT'));
|
|
83
|
+
for (const file of files.values()) {
|
|
84
|
+
const local = new Map();
|
|
85
|
+
const isExport = basename(file.path) === 'export.aug';
|
|
86
|
+
for (const item of file.items) {
|
|
87
|
+
if (isExport && item.kind !== 'export') {
|
|
88
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'export.aug may contain only export declarations', 'EXPORT'));
|
|
89
|
+
}
|
|
90
|
+
if (!isExport && item.kind === 'export') {
|
|
91
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'export declarations belong in export.aug', 'EXPORT'));
|
|
92
|
+
}
|
|
93
|
+
if (file === main && ['class', 'interface', 'function', 'interceptor', 'test', 'composition'].includes(item.kind)) {
|
|
94
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'Define classes, interfaces, functions, and interceptors outside main.aug', 'MAIN'));
|
|
95
|
+
}
|
|
96
|
+
if (file !== main && ['bind', 'include', 'expr', 'assign', 'return', 'throw', 'if', 'while', 'for', 'destructure', 'match', 'scope', 'freeze', 'serve', 'lock',
|
|
97
|
+
'try', 'unsafe', 'borrow'].includes(item.kind)) {
|
|
98
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'Executable statements and bindings belong in main.aug', 'MAIN'));
|
|
99
|
+
}
|
|
100
|
+
if (item.kind === 'class' || item.kind === 'interface' || item.kind === 'function' || item.kind === 'interceptor' || item.kind === 'composition') {
|
|
101
|
+
if (item.name in builtinTypes || builtinFunctions.some(operation => operation.name === item.name) || item.name === 'next') {
|
|
102
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `${item.name} is a reserved built-in name`, 'NAME'));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (local.has(item.name)) {
|
|
106
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `Duplicate declaration ${item.name}`, 'NAME'));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const packageScope = file.package ? packages.scopes.get(file.package) : undefined;
|
|
110
|
+
const identity = packageScope ? `package/${packageScope.name}@${packageScope.version}/${relative(packageScope.sourceRoot, file.path)}` :
|
|
111
|
+
library && !file.builtin ? `package/${library.name}@${library.version}/${relative(sourceRoot, file.path)}` : relative(root, file.path);
|
|
112
|
+
const def = { id: `${file.builtin ? 'august/' + libraryRelative(libraries, file.path) : identity}:${item.name}`,
|
|
113
|
+
name: item.name, file: file.path, node: item };
|
|
114
|
+
local.set(item.name, def);
|
|
115
|
+
definitions.set(def.id, def);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
scopes.set(file.path, local);
|
|
119
|
+
}
|
|
120
|
+
// Importing a sibling exposes its declarations, never its imported dependencies.
|
|
121
|
+
const declaredScopes = new Map([...scopes].map(([file, scope]) => [file, new Map(scope)]));
|
|
122
|
+
const exportCache = new Map();
|
|
123
|
+
function folderExports(folder, visiting = new Set()) {
|
|
124
|
+
if (exportCache.has(folder))
|
|
125
|
+
return exportCache.get(folder);
|
|
126
|
+
const result = new Map();
|
|
127
|
+
const exportFile = files.get(join(folder, 'export.aug'));
|
|
128
|
+
if (!exportFile)
|
|
129
|
+
return result;
|
|
130
|
+
if (visiting.has(folder))
|
|
131
|
+
return result;
|
|
132
|
+
visiting.add(folder);
|
|
133
|
+
for (const item of exportFile.items) {
|
|
134
|
+
if (item.kind !== 'export' || item.folder)
|
|
135
|
+
continue;
|
|
136
|
+
if (isPrivateName(item.name)) {
|
|
137
|
+
diagnostics.push(diagnostic(exportFile.path, item.span.line, item.span.column, `Cannot export private name ${item.name}`, 'PRIVATE'));
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (item.from && isPrivateName(item.from)) {
|
|
141
|
+
diagnostics.push(diagnostic(exportFile.path, item.span.line, item.span.column, `Cannot export from private module ${item.from}`, 'PRIVATE'));
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const sibling = files.get(join(folder, `${item.from}.aug`));
|
|
145
|
+
if (!sibling || basename(sibling.path) === 'export.aug') {
|
|
146
|
+
diagnostics.push(diagnostic(exportFile.path, item.span.line, item.span.column, `Cannot export ${item.name}: sibling file ${item.from}.aug was not found`, 'EXPORT'));
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const def = declaredScopes.get(sibling.path)?.get(item.name);
|
|
150
|
+
if (!def) {
|
|
151
|
+
diagnostics.push(diagnostic(exportFile.path, item.span.line, item.span.column, `Cannot export ${item.name}: ${item.from}.aug does not define it`, 'EXPORT'));
|
|
152
|
+
}
|
|
153
|
+
else if (result.has(item.name)) {
|
|
154
|
+
diagnostics.push(diagnostic(exportFile.path, item.span.line, item.span.column, `Duplicate export ${item.name}`, 'EXPORT'));
|
|
155
|
+
}
|
|
156
|
+
else
|
|
157
|
+
result.set(item.name, def);
|
|
158
|
+
}
|
|
159
|
+
exportCache.set(folder, result);
|
|
160
|
+
visiting.delete(folder);
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
function exposedChild(folder, child) {
|
|
164
|
+
const file = files.get(join(folder, 'export.aug'));
|
|
165
|
+
return !!file?.items.some((item) => item.kind === 'export' && item.folder && item.name === child);
|
|
166
|
+
}
|
|
167
|
+
for (const file of files.values()) {
|
|
168
|
+
if (basename(file.path) !== 'export.aug')
|
|
169
|
+
continue;
|
|
170
|
+
for (const item of file.items) {
|
|
171
|
+
if (item.kind !== 'export' || !item.folder)
|
|
172
|
+
continue;
|
|
173
|
+
if (isPrivateName(item.name)) {
|
|
174
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `Cannot export private folder ${item.name}`, 'PRIVATE'));
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const path = file.builtin ? libraryChild(libraries, dirname(file.path), item.name) : join(dirname(file.path), item.name);
|
|
178
|
+
if (!statExistsDirectory(path))
|
|
179
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `Cannot export folder ${item.name}: it does not exist`, 'EXPORT'));
|
|
180
|
+
else if (!files.has(join(path, 'export.aug')))
|
|
181
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `Cannot export folder ${item.name}: it has no export.aug`, 'EXPORT'));
|
|
182
|
+
}
|
|
183
|
+
folderExports(dirname(file.path));
|
|
184
|
+
}
|
|
185
|
+
for (const file of files.values()) {
|
|
186
|
+
if (basename(file.path) === 'export.aug')
|
|
187
|
+
continue;
|
|
188
|
+
const scope = scopes.get(file.path);
|
|
189
|
+
for (const item of file.items) {
|
|
190
|
+
if (item.kind !== 'import')
|
|
191
|
+
continue;
|
|
192
|
+
const resolved = resolveImports(item, file.path);
|
|
193
|
+
imports.set(item, [...resolved.values()]);
|
|
194
|
+
for (const [name, def] of resolved) {
|
|
195
|
+
if (scope.has(name))
|
|
196
|
+
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `Imported name ${name} conflicts with another name`, 'IMPORT'));
|
|
197
|
+
else
|
|
198
|
+
scope.set(name, def);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function resolveImports(item, importer) {
|
|
203
|
+
const source = item.from.join('.');
|
|
204
|
+
const result = new Map();
|
|
205
|
+
const select = (available, missing) => {
|
|
206
|
+
const names = item.everything ? [...available.keys()].filter(name => !isPrivateName(name)) : item.names;
|
|
207
|
+
for (const name of names) {
|
|
208
|
+
if (isPrivateName(name))
|
|
209
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Cannot import private name ${name}`, 'PRIVATE'));
|
|
210
|
+
else if (result.has(name))
|
|
211
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Duplicate imported name ${name}`, 'IMPORT'));
|
|
212
|
+
else if (available.has(name))
|
|
213
|
+
result.set(name, available.get(name));
|
|
214
|
+
else
|
|
215
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `${source} ${missing} ${name}`, 'IMPORT'));
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
};
|
|
219
|
+
const privateModule = item.from.find(isPrivateName);
|
|
220
|
+
if (privateModule) {
|
|
221
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Cannot import from private module ${privateModule}`, 'PRIVATE'));
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
if (item.from[0] === 'august') {
|
|
225
|
+
let folder = stdlibRoot;
|
|
226
|
+
for (const child of item.from.slice(1)) {
|
|
227
|
+
if (!exposedChild(folder, child)) {
|
|
228
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Standard module august does not export ${child}`, 'IMPORT'));
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
folder = libraryChild(libraries, folder, child);
|
|
232
|
+
}
|
|
233
|
+
return select(folderExports(folder), 'does not export');
|
|
234
|
+
}
|
|
235
|
+
const owner = files.get(importer)?.package;
|
|
236
|
+
const ownerScope = owner ? packages.scopes.get(owner) : undefined;
|
|
237
|
+
const dependency = ownerScope ? packages.scopes.get(ownerScope.dependencies[item.from[0]]) : packages.roots.get(item.from[0]);
|
|
238
|
+
if (dependency) {
|
|
239
|
+
let folder = dependency.sourceRoot;
|
|
240
|
+
for (const child of item.from.slice(1)) {
|
|
241
|
+
if (!exposedChild(folder, child)) {
|
|
242
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Package ${item.from[0]} does not export folder ${child}`, 'IMPORT'));
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
folder = join(folder, child);
|
|
246
|
+
}
|
|
247
|
+
return select(folderExports(folder), 'does not export');
|
|
248
|
+
}
|
|
249
|
+
if (item.from.length === 1) {
|
|
250
|
+
const sibling = join(dirname(importer), `${item.from[0]}.aug`);
|
|
251
|
+
if (files.has(sibling) && basename(sibling) !== 'export.aug') {
|
|
252
|
+
return select(declaredScopes.get(sibling) ?? new Map(), 'does not define');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
let folder;
|
|
256
|
+
if (item.from.length === 1 && statExistsDirectory(join(dirname(importer), item.from[0]))) {
|
|
257
|
+
folder = join(dirname(importer), item.from[0]);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
folder = join(ownerScope?.sourceRoot ?? sourceRoot, item.from[0]);
|
|
261
|
+
if (!statExistsDirectory(folder)) {
|
|
262
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Import folder ${source} does not exist`, 'IMPORT'));
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
for (const child of item.from.slice(1)) {
|
|
266
|
+
if (!exposedChild(folder, child)) {
|
|
267
|
+
diagnostics.push(diagnostic(importer, item.span.line, item.span.column, `Folder ${relative(root, folder)} does not export child folder ${child}`, 'IMPORT'));
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
270
|
+
folder = join(folder, child);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return select(folderExports(folder), 'does not export');
|
|
274
|
+
}
|
|
275
|
+
const project = { root, sourceRoot, library, packages, files, definitions, scopes, imports, diagnostics, main, stdlibRoot, libraries, config };
|
|
276
|
+
diagnostics.push(...projectPolicies(project));
|
|
277
|
+
return project;
|
|
278
|
+
}
|
|
279
|
+
function statExistsDirectory(path) {
|
|
280
|
+
try {
|
|
281
|
+
return statSync(path).isDirectory();
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
export function declarations(file) {
|
|
288
|
+
return file.items.filter((item) => item.kind === 'class' || item.kind === 'interface' || item.kind === 'function' || item.kind === 'interceptor' || item.kind === 'composition');
|
|
289
|
+
}
|
|
290
|
+
export function statements(file) {
|
|
291
|
+
return file.items.filter(item => !['import', 'export', 'class', 'interface', 'function', 'interceptor', 'composition', 'test'].includes(item.kind));
|
|
292
|
+
}
|
package/src/schemas.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function schemaType(project, ref, file, parameters = new Map()) {
|
|
2
|
+
const param = parameters.get(ref.name);
|
|
3
|
+
if (param)
|
|
4
|
+
return { ...param, nullable: param.nullable || ref.nullable, optional: ref.optional || param.optional };
|
|
5
|
+
const def = project.scopes.get(file)?.get(ref.name);
|
|
6
|
+
return { id: def?.id ?? 'builtin:' + ref.name, name: ref.name,
|
|
7
|
+
kind: def?.node.kind === 'class' ? 'class' : def ? 'interface' : 'builtin', def,
|
|
8
|
+
nullable: ref.nullable, optional: ref.optional, args: ref.args.map(arg => schemaType(project, arg, file, parameters)) };
|
|
9
|
+
}
|
|
10
|
+
export function jsonDataType(project, type, seen = new Set()) {
|
|
11
|
+
if (['int', 'c_int', 'float', 'bool', 'string', 'Json'].includes(type.name) && type.kind === 'builtin')
|
|
12
|
+
return true;
|
|
13
|
+
if (type.kind === 'builtin' && ['List', 'Set', 'Tuple', 'Map'].includes(type.name))
|
|
14
|
+
return (type.name !== 'Map' || type.args[0]?.name === 'string') && type.args.every(arg => jsonDataType(project, arg, seen));
|
|
15
|
+
const node = type.def?.node;
|
|
16
|
+
if (node?.kind !== 'class' || !node.record || node.fields.some(field => field.name.startsWith('_')))
|
|
17
|
+
return false;
|
|
18
|
+
if (seen.has(type.id))
|
|
19
|
+
return true;
|
|
20
|
+
seen.add(type.id);
|
|
21
|
+
const params = new Map(node.typeParams.map((name, i) => [name, type.args[i]]));
|
|
22
|
+
return node.fields.every(field => jsonDataType(project, schemaType(project, field.type, type.def.file, params), seen));
|
|
23
|
+
}
|
|
24
|
+
/** One shared native schema per concrete type, used by HTTP and explicit JSON decoding. */
|
|
25
|
+
export class NativeSchemas {
|
|
26
|
+
names = new Map();
|
|
27
|
+
output = [];
|
|
28
|
+
forwards = [];
|
|
29
|
+
project;
|
|
30
|
+
constructorName;
|
|
31
|
+
constructor(project, constructorName) {
|
|
32
|
+
this.project = project;
|
|
33
|
+
this.constructorName = constructorName;
|
|
34
|
+
}
|
|
35
|
+
request(type) {
|
|
36
|
+
const key = JSON.stringify(this.identity(type));
|
|
37
|
+
const previous = this.names.get(key);
|
|
38
|
+
if (previous)
|
|
39
|
+
return previous;
|
|
40
|
+
const name = 'aug_schema_' + this.names.size;
|
|
41
|
+
this.names.set(key, name);
|
|
42
|
+
this.forwards.push(`static const AugSchema ${name};`);
|
|
43
|
+
let kind = 'AUG_SCHEMA_' + type.name.toUpperCase(), fields = [], labels = [], maker = 'NULL';
|
|
44
|
+
if (type.def?.node.kind === 'class' && type.def.node.record) {
|
|
45
|
+
kind = 'AUG_SCHEMA_RECORD';
|
|
46
|
+
const node = type.def.node, params = new Map(node.typeParams.map((param, i) => [param, type.args[i]]));
|
|
47
|
+
fields = node.fields.map(field => '&' + this.request(schemaType(this.project, field.type, type.def.file, params)));
|
|
48
|
+
labels = node.fields.map(field => JSON.stringify(field.name));
|
|
49
|
+
maker = this.constructorName(type.def);
|
|
50
|
+
}
|
|
51
|
+
else
|
|
52
|
+
fields = type.args.map(arg => '&' + this.request(arg));
|
|
53
|
+
if (fields.length)
|
|
54
|
+
this.output.push(`static const AugSchema *const ${name}_fields[] = {${fields.join(', ')}};`);
|
|
55
|
+
if (labels.length)
|
|
56
|
+
this.output.push(`static const char *const ${name}_names[] = {${labels.join(', ')}};`);
|
|
57
|
+
this.output.push(`static const AugSchema ${name} = {${kind}, ${type.nullable ? 'true' : 'false'}, ${type.optional ? 'true' : 'false'}, ${fields.length}, ${fields.length ? name + '_fields' : 'NULL'}, ${labels.length ? name + '_names' : 'NULL'}, ${maker}};`);
|
|
58
|
+
return name;
|
|
59
|
+
}
|
|
60
|
+
identity(type) { return [type.id, type.nullable, !!type.optional, type.args.map(arg => this.identity(arg))]; }
|
|
61
|
+
declarations() { return [...this.forwards, ...this.output].join('\n'); }
|
|
62
|
+
}
|