From 8f49fd2d1afbfe0421f57b629c9135588b4fe419 Mon Sep 17 00:00:00 2001 From: Peefy Date: Tue, 2 Dec 2025 19:15:13 +0800 Subject: [PATCH] feat: add 0.12 docs Signed-off-by: Peefy --- .gitignore | 3 +- VERSION | 2 +- blog/2024-11-14-newsletter/index.md | 2 +- blog/2024-12-24-kcl-0.11.0-release/index.md | 13 +- docs/reference/model/net.md | 4 +- docs/reference/xlang-api/c-api.md | 20 +- docs/reference/xlang-api/cpp-api.md | 2 +- docs/reference/xlang-api/dotnet-api.md | 48 +- docs/reference/xlang-api/go-api.md | 229 +- docs/reference/xlang-api/java-api.md | 92 +- docs/reference/xlang-api/kotlin-api.md | 2 +- docs/reference/xlang-api/overview.md | 24 +- docs/reference/xlang-api/python-api.md | 46 +- docs/reference/xlang-api/rest-api.md | 180 +- docs/reference/xlang-api/swift-api.md | 2 +- docs/tools/Ide/helix.md | 3 + .../working-with-konfig/3-quick-start.md | 84 +- .../working-with-konfig/4-best-practice.md | 6 +- docs/user_docs/support/faq-kcl.md | 5 +- .../2024-12-24-kcl-0.11.0-release/index.md | 17 +- .../current/reference/model/regex.md | 1 + .../version-0.10/reference/model/regex.md | 1 + .../version-0.11.json | 136 + .../version-0.11/reference/model/regex.md | 1 + .../version-0.12.json | 136 + .../version-0.12/community/_category_.json | 4 + .../community/contribute/_category_.json | 4 + .../community/contribute/contribute-code.md | 25 + .../community/contribute/contribute-docs.md | 61 + .../community/contribute/contribute.md | 1 + .../community/contribute/git-guideline.md | 132 + .../community/intro/_category_.json | 4 + .../version-0.12/community/intro/intro.md | 9 + .../version-0.12/community/intro/license.md | 211 + .../version-0.12/community/intro/support.md | 19 + .../community/release-policy/_category_.json | 4 + .../community/release-policy/index.md | 1 + .../community/release-policy/kcl.md | 33 + .../community/release-policy/roadmap.md | 4 + .../version-0.12/reference/_category_.json | 4 + .../reference/cheatsheets/_category_.json | 4 + .../reference/cheatsheets/index.md | 5 + .../version-0.12/reference/index.md | 1 + .../reference/lang/_category_.json | 4 + .../reference/lang/codelab/_category_.json | 4 + .../reference/lang/codelab/collaborative.md | 345 ++ .../reference/lang/codelab/index.md | 1 + .../reference/lang/codelab/schema.md | 817 ++++ .../reference/lang/codelab/simple.md | 495 +++ .../reference/lang/error/_category_.json | 4 + .../reference/lang/error/exception.md | 1509 ++++++++ .../reference/lang/error/index.md | 1 + .../version-0.12/reference/lang/index.md | 1 + .../reference/lang/spec/_category_.json | 4 + .../reference/lang/spec/codestyle.md | 624 +++ .../reference/lang/spec/datatypes.md | 452 +++ .../version-0.12/reference/lang/spec/error.md | 53 + .../reference/lang/spec/expressions.md | 915 +++++ .../version-0.12/reference/lang/spec/index.md | 1 + .../reference/lang/spec/kcl-spec.md | 339 ++ .../reference/lang/spec/lexical.md | 213 ++ .../reference/lang/spec/modules.md | 350 ++ .../reference/lang/spec/schema.md | 916 +++++ .../reference/lang/spec/statements.md | 185 + .../reference/lang/spec/variables.md | 68 + .../version-0.12/reference/lang/tour.md | 3281 ++++++++++++++++ .../reference/lang/types/_category_.json | 4 + .../reference/lang/types/types.md | 1401 +++++++ .../reference/model/_category_.json | 4 + .../version-0.12/reference/model/base64.md | 31 + .../version-0.12/reference/model/builtin.md | 415 ++ .../version-0.12/reference/model/crypto.md | 139 + .../version-0.12/reference/model/datetime.md | 67 + .../version-0.12/reference/model/file.md | 175 + .../version-0.12/reference/model/json.md | 111 + .../version-0.12/reference/model/manifests.md | 89 + .../version-0.12/reference/model/math.md | 216 ++ .../version-0.12/reference/model/net.md | 201 + .../version-0.12/reference/model/overview.md | 63 + .../version-0.12/reference/model/regex.md | 79 + .../version-0.12/reference/model/runtime.md | 30 + .../version-0.12/reference/model/template.md | 48 + .../version-0.12/reference/model/units.md | 60 + .../version-0.12/reference/model/yaml.md | 173 + .../reference/plugin/_category_.json | 4 + .../version-0.12/reference/plugin/overview.md | 249 ++ .../reference/xlang-api/_category_.json | 4 + .../version-0.12/reference/xlang-api/c-api.md | 172 + .../reference/xlang-api/cpp-api.md | 628 +++ .../reference/xlang-api/dotnet-api.md | 614 +++ .../reference/xlang-api/go-api.md | 1138 ++++++ .../reference/xlang-api/java-api.md | 623 +++ .../reference/xlang-api/kotlin-api.md | 605 +++ .../reference/xlang-api/lua-api.md | 13 + .../reference/xlang-api/nodejs-api.md | 590 +++ .../reference/xlang-api/overview.md | 125 + .../reference/xlang-api/python-api.md | 673 ++++ .../reference/xlang-api/rest-api.md | 1590 ++++++++ .../reference/xlang-api/rust-api.md | 320 ++ .../reference/xlang-api/swift-api.md | 18 + .../reference/xlang-api/wasm-api.md | 248 ++ .../version-0.12/tools/Ide/_category_.json | 4 + .../version-0.12/tools/Ide/index.md | 7 + .../version-0.12/tools/Ide/intellij.md | 63 + .../version-0.12/tools/Ide/neovim.md | 9 + .../version-0.12/tools/Ide/vs-code.md | 73 + .../version-0.12/tools/_category_.json | 4 + .../version-0.12/tools/cli/_category_.json | 4 + .../version-0.12/tools/cli/index.md | 3 + .../tools/cli/kcl/_category_.json | 4 + .../version-0.12/tools/cli/kcl/docgen.md | 162 + .../version-0.12/tools/cli/kcl/fmt.md | 89 + .../version-0.12/tools/cli/kcl/import.md | 62 + .../version-0.12/tools/cli/kcl/index.md | 3 + .../version-0.12/tools/cli/kcl/lint.md | 79 + .../version-0.12/tools/cli/kcl/overview.md | 61 + .../version-0.12/tools/cli/kcl/run.md | 60 + .../version-0.12/tools/cli/kcl/test.md | 187 + .../version-0.12/tools/cli/kcl/vet.md | 88 + .../tools/cli/openapi/_category_.json | 4 + .../tools/cli/openapi/crd-to-kcl.md | 118 + .../tools/cli/openapi/openapi-to-kcl.md | 64 + .../version-0.12/tools/cli/openapi/spec.md | 424 +++ .../cli/package-management/_category_.json | 4 + .../command-reference/1.init.md | 72 + .../command-reference/10.help.md | 21 + .../command-reference/11.update.md | 46 + .../command-reference/12.graph.md | 37 + .../command-reference/2.add.md | 97 + .../command-reference/3.pkg.md | 60 + .../command-reference/4.metadata.md | 68 + .../command-reference/6.login.md | 96 + .../command-reference/7.logout.md | 47 + .../command-reference/8.push.md | 70 + .../command-reference/9.pull.md | 80 + .../command-reference/_category_.json | 4 + .../user_docs/concepts/_category_.json | 4 + .../user_docs/concepts/concepts.md | 7 + .../user_docs/concepts/package-and-module.md | 156 + .../user_docs/concepts/type-and-definition.md | 94 + .../user_docs/getting-started/_category_.json | 4 + .../user_docs/getting-started/index.md | 5 + .../user_docs/getting-started/install.md | 219 ++ .../user_docs/getting-started/intro.md | 216 ++ .../getting-started/kcl-quick-start.md | 169 + .../user_docs/guides/_category_.json | 4 + .../user_docs/guides/abstraction.md | 151 + .../user_docs/guides/automation.md | 195 + .../guides/ci-integration/1-github-actions.md | 166 + .../guides/ci-integration/_2-gitlab-ci.md | 12 + .../guides/ci-integration/_3-jenkins-ci.md | 12 + .../guides/ci-integration/_category_.json | 4 + .../user_docs/guides/configuration.md | 129 + .../user_docs/guides/data-integration.md | 117 + .../user_docs/guides/gitops/1-argocd.md | 145 + .../user_docs/guides/gitops/2-fluxcd.md | 112 + .../user_docs/guides/gitops/_category_.json | 4 + .../version-0.12/user_docs/guides/index.md | 7 + .../package-management/3-quick-start.md | 106 + .../package-management/4-how-to/10-kpm_git.md | 33 + .../4-how-to/4-share_your_pkg.md | 73 + .../4-how-to/5-share_your_pkg_docker.md | 65 + .../4-how-to/6-push_github_action.md | 83 + .../4-how-to/7-publish_pkg_to_ah.md | 142 + .../package-management/4-how-to/8-kcl_mod.md | 243 ++ .../package-management/4-how-to/9-kpm_oci.md | 229 ++ .../4-how-to/_category_.json | 4 + .../guides/package-management/_category_.json | 4 + .../user_docs/guides/schema-definition.md | 117 + .../guides/secret-management/1-vault.md | 142 + .../guides/secret-management/_category_.json | 4 + .../user_docs/guides/validation.md | 93 + .../guides/working-with-k8s/0-overview.md | 33 + .../1-adapt-from-kubernetes.md | 194 + .../2-generate-k8s-manifests.md | 316 ++ .../1-kubectl-kcl-plugin.md | 207 + .../3-mutate-manifests/2-helm-kcl-plugin.md | 100 + .../3-kustomize-kcl-plugin.md | 104 + .../3-mutate-manifests/4-kpt-kcl-sdk.md | 87 + .../3-mutate-manifests/_category_.json | 4 + .../working-with-k8s/4-publish-modules.md | 91 + .../guides/working-with-k8s/_category_.json | 4 + .../guides/working-with-k8s/index.md | 1 + .../guides/working-with-konfig/1-overview.md | 47 + .../guides/working-with-konfig/2-structure.md | 37 + .../working-with-konfig/3-quick-start.md | 230 ++ .../working-with-konfig/4-best-practice.md | 271 ++ .../working-with-konfig/_category_.json | 4 + .../working-with-kubevela/_category_.json | 4 + .../guides/working-with-kubevela/index.md | 99 + .../working-with-kusion/_category_.json | 4 + .../guides/working-with-kusion/index.md | 15 + .../user_docs/support/_category_.json | 4 + .../version-0.12/user_docs/support/faq-cli.md | 107 + .../user_docs/support/faq-install.md | 56 + .../version-0.12/user_docs/support/faq-kcl.md | 2681 +++++++++++++ .../user_docs/support/faq-yaml.md | 104 + .../version-0.12/user_docs/support/support.md | 7 + package-lock.json | 4 +- package.json | 2 +- src/components/Form/index.tsx | 7 +- .../version-0.10/user_docs/support/faq-kcl.md | 2 - .../version-0.11/user_docs/support/faq-kcl.md | 5 +- .../community/contribute/_category_.json | 4 + .../community/contribute/contribute-code.md | 19 + .../community/contribute/contribute-docs.md | 52 + .../community/contribute/contribute.md | 3 + .../community/contribute/git-guideline.md | 128 + .../community/intro/_category_.json | 4 + .../version-0.12/community/intro/intro.md | 9 + .../version-0.12/community/intro/license.md | 211 + .../version-0.12/community/intro/support.md | 21 + .../community/release-policy/_category_.json | 4 + .../community/release-policy/index.md | 3 + .../community/release-policy/kcl.md | 33 + .../community/release-policy/roadmap.md | 4 + .../version-0.12/reference/_category_.json | 4 + .../reference/cheatsheets/_category_.json | 4 + .../reference/cheatsheets/index.md | 5 + .../reference/lang/_category_.json | 4 + .../reference/lang/codelab/_category_.json | 4 + .../reference/lang/codelab/collaborative.md | 345 ++ .../reference/lang/codelab/index.md | 1 + .../reference/lang/codelab/schema.md | 827 ++++ .../reference/lang/codelab/simple.md | 495 +++ .../reference/lang/error/_category_.json | 4 + .../reference/lang/error/exception.md | 1367 +++++++ .../reference/lang/error/index.md | 1 + .../reference/lang/spec/_category_.json | 4 + .../reference/lang/spec/codestyle.md | 624 +++ .../reference/lang/spec/datatypes.md | 452 +++ .../version-0.12/reference/lang/spec/error.md | 53 + .../reference/lang/spec/expressions.md | 913 +++++ .../version-0.12/reference/lang/spec/index.md | 1 + .../reference/lang/spec/kcl-spec.md | 339 ++ .../reference/lang/spec/lexical.md | 213 ++ .../reference/lang/spec/modules.md | 350 ++ .../reference/lang/spec/schema.md | 916 +++++ .../reference/lang/spec/statements.md | 185 + .../reference/lang/spec/variables.md | 68 + .../version-0.12/reference/lang/tour.md | 3383 +++++++++++++++++ .../reference/lang/types/_category_.json | 4 + .../reference/lang/types/types.md | 1381 +++++++ .../reference/model/_category_.json | 4 + .../version-0.12/reference/model/base64.md | 31 + .../version-0.12/reference/model/builtin.md | 400 ++ .../version-0.12/reference/model/crypto.md | 139 + .../version-0.12/reference/model/datetime.md | 67 + .../version-0.12/reference/model/file.md | 175 + .../version-0.12/reference/model/json.md | 111 + .../version-0.12/reference/model/manifests.md | 89 + .../version-0.12/reference/model/math.md | 216 ++ .../version-0.12/reference/model/net.md | 201 + .../version-0.12/reference/model/overview.md | 63 + .../version-0.12/reference/model/regex.md | 79 + .../version-0.12/reference/model/runtime.md | 30 + .../version-0.12/reference/model/template.md | 48 + .../version-0.12/reference/model/units.md | 60 + .../version-0.12/reference/model/yaml.md | 172 + .../reference/plugin/_category_.json | 4 + .../version-0.12/reference/plugin/overview.md | 250 ++ .../reference/xlang-api/_category_.json | 4 + .../version-0.12/reference/xlang-api/c-api.md | 172 + .../reference/xlang-api/cpp-api.md | 628 +++ .../reference/xlang-api/dotnet-api.md | 614 +++ .../reference/xlang-api/go-api.md | 1138 ++++++ .../reference/xlang-api/java-api.md | 623 +++ .../reference/xlang-api/kotlin-api.md | 605 +++ .../reference/xlang-api/lua-api.md | 13 + .../reference/xlang-api/nodejs-api.md | 590 +++ .../reference/xlang-api/overview.md | 125 + .../reference/xlang-api/python-api.md | 673 ++++ .../reference/xlang-api/rest-api.md | 1590 ++++++++ .../reference/xlang-api/rust-api.md | 320 ++ .../reference/xlang-api/swift-api.md | 18 + .../reference/xlang-api/wasm-api.md | 248 ++ .../version-0.12/tools/Ide/_category_.json | 4 + .../version-0.12/tools/Ide/index.md | 7 + .../version-0.12/tools/Ide/intellij.md | 63 + .../version-0.12/tools/Ide/neovim.md | 9 + .../version-0.12/tools/Ide/vs-code.md | 73 + .../version-0.12/tools/_category_.json | 4 + .../version-0.12/tools/cli/_category_.json | 4 + .../version-0.12/tools/cli/index.md | 3 + .../tools/cli/kcl/_category_.json | 4 + .../version-0.12/tools/cli/kcl/docgen.md | 162 + .../version-0.12/tools/cli/kcl/fmt.md | 85 + .../version-0.12/tools/cli/kcl/import.md | 62 + .../version-0.12/tools/cli/kcl/index.md | 3 + .../version-0.12/tools/cli/kcl/lint.md | 79 + .../version-0.12/tools/cli/kcl/overview.md | 61 + .../version-0.12/tools/cli/kcl/run.md | 62 + .../version-0.12/tools/cli/kcl/test.md | 187 + .../version-0.12/tools/cli/kcl/vet.md | 82 + .../tools/cli/openapi/_category_.json | 4 + .../tools/cli/openapi/crd-to-kcl.md | 118 + .../tools/cli/openapi/openapi-to-kcl.md | 64 + .../version-0.12/tools/cli/openapi/spec.md | 438 +++ .../cli/package-management/_category_.json | 4 + .../command-reference/1.init.md | 72 + .../command-reference/10.help.md | 21 + .../command-reference/11.update.md | 58 + .../command-reference/12.graph.md | 47 + .../command-reference/2.add.md | 97 + .../command-reference/3.pkg.md | 60 + .../command-reference/4.metadata.md | 68 + .../command-reference/6.login.md | 96 + .../command-reference/7.logout.md | 47 + .../command-reference/8.push.md | 70 + .../command-reference/9.pull.md | 81 + .../command-reference/_category_.json | 4 + .../user_docs/concepts/_category_.json | 4 + .../user_docs/concepts/concepts.md | 7 + .../user_docs/concepts/package-and-module.md | 156 + .../user_docs/concepts/type-and-definition.md | 94 + .../user_docs/getting-started/_category_.json | 4 + .../user_docs/getting-started/index.md | 7 + .../user_docs/getting-started/install.md | 219 ++ .../user_docs/getting-started/intro.md | 217 ++ .../getting-started/kcl-quick-start.md | 169 + .../user_docs/guides/_category_.json | 4 + .../user_docs/guides/abstraction.md | 153 + .../user_docs/guides/automation.md | 193 + .../guides/ci-integration/1-github-actions.md | 166 + .../guides/ci-integration/2-gitlab-ci.md | 139 + .../guides/ci-integration/_3-jenkins-ci.md | 12 + .../guides/ci-integration/_category_.json | 4 + .../user_docs/guides/configuration.md | 129 + .../user_docs/guides/data-integration.md | 117 + .../user_docs/guides/gitops/1-argocd.md | 163 + .../user_docs/guides/gitops/2-fluxcd.md | 114 + .../user_docs/guides/gitops/_category_.json | 4 + .../version-0.12/user_docs/guides/index.md | 7 + .../package-management/3-quick-start.md | 106 + .../package-management/4-how-to/10-kpm_git.md | 36 + .../4-how-to/4-share_your_pkg.md | 73 + .../4-how-to/5-share_your_pkg_docker.md | 64 + .../4-how-to/6-push_github_action.md | 81 + .../4-how-to/7-publish_pkg_to_ah.md | 146 + .../package-management/4-how-to/8-kcl_mod.md | 148 + .../package-management/4-how-to/9-kpm_oci.md | 222 ++ .../4-how-to/_category_.json | 4 + .../guides/package-management/_category_.json | 4 + .../user_docs/guides/schema-definition.md | 139 + .../guides/secret-management/1-vault.md | 142 + .../guides/secret-management/_category_.json | 4 + .../user_docs/guides/validation.md | 93 + .../guides/working-with-k8s/0-overview.md | 33 + .../1-adapt-from-kubernetes.md | 196 + .../2-generate-k8s-manifests.md | 316 ++ .../1-kubectl-kcl-plugin.md | 207 + .../3-mutate-manifests/2-helm-kcl-plugin.md | 102 + .../3-kustomize-kcl-plugin.md | 107 + .../3-mutate-manifests/4-kpt-kcl-sdk.md | 98 + .../5-helmfile-kcl-plugin.md | 115 + .../3-mutate-manifests/6-kcl-operator.md | 94 + .../7-crossplane-kcl-function.md | 240 ++ .../3-mutate-manifests/_category_.json | 4 + .../guides/working-with-k8s/_category_.json | 4 + .../guides/working-with-konfig/1-overview.md | 47 + .../guides/working-with-konfig/2-structure.md | 37 + .../working-with-konfig/3-quick-start.md | 208 + .../working-with-konfig/4-best-practice.md | 449 +++ .../working-with-konfig/_category_.json | 4 + .../working-with-kubevela/_category_.json | 4 + .../guides/working-with-kubevela/index.md | 99 + .../working-with-kusion/_category_.json | 4 + .../guides/working-with-kusion/index.md | 15 + .../working-with-terraform/3-validation.md | 493 +++ .../_1-adapt-from-terraform.md | 8 + .../working-with-terraform/_2-abstraction.md | 8 + .../working-with-terraform/_category_.json | 4 + .../user_docs/support/_category_.json | 4 + .../version-0.12/user_docs/support/faq-cli.md | 107 + .../user_docs/support/faq-install.md | 56 + .../version-0.12/user_docs/support/faq-kcl.md | 2722 +++++++++++++ .../user_docs/support/faq-yaml.md | 102 + .../version-0.12/user_docs/support/support.md | 7 + versioned_sidebars/version-0.12-sidebars.json | 32 + versions.json | 1 + 380 files changed, 66538 insertions(+), 440 deletions(-) create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-code.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-docs.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/git-guideline.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/intro.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/license.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/support.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/kcl.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/roadmap.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/collaborative.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/schema.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/simple.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/exception.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/codestyle.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/datatypes.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/error.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/expressions.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/kcl-spec.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/lexical.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/modules.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/schema.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/statements.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/variables.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/tour.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/types.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/base64.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/builtin.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/crypto.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/datetime.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/file.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/json.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/manifests.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/math.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/net.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/overview.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/regex.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/runtime.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/template.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/units.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/yaml.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/overview.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/c-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/cpp-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/dotnet-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/go-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/java-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/kotlin-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/lua-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/nodejs-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/overview.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/python-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rest-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rust-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/swift-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/wasm-api.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/intellij.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/neovim.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/vs-code.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/docgen.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/fmt.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/import.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/lint.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/overview.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/run.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/test.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/vet.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/crd-to-kcl.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/openapi-to-kcl.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/spec.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/1.init.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/10.help.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/11.update.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/12.graph.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/2.add.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/3.pkg.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/4.metadata.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/6.login.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/7.logout.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/8.push.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/9.pull.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/concepts.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/package-and-module.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/type-and-definition.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/install.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/intro.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/kcl-quick-start.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/abstraction.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/automation.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/1-github-actions.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_2-gitlab-ci.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_3-jenkins-ci.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/configuration.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/data-integration.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/1-argocd.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/2-fluxcd.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/3-quick-start.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/10-kpm_git.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/4-share_your_pkg.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/5-share_your_pkg_docker.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/6-push_github_action.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/7-publish_pkg_to_ah.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/8-kcl_mod.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/9-kpm_oci.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/schema-definition.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/1-vault.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/validation.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/0-overview.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/1-adapt-from-kubernetes.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/2-generate-k8s-manifests.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/1-kubectl-kcl-plugin.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/2-helm-kcl-plugin.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/3-kustomize-kcl-plugin.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/4-kpt-kcl-sdk.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/4-publish-modules.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/1-overview.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/2-structure.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/3-quick-start.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/4-best-practice.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/index.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/_category_.json create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-cli.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-install.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-kcl.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-yaml.md create mode 100644 i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/support.md create mode 100644 versioned_docs/version-0.12/community/contribute/_category_.json create mode 100644 versioned_docs/version-0.12/community/contribute/contribute-code.md create mode 100644 versioned_docs/version-0.12/community/contribute/contribute-docs.md create mode 100644 versioned_docs/version-0.12/community/contribute/contribute.md create mode 100644 versioned_docs/version-0.12/community/contribute/git-guideline.md create mode 100644 versioned_docs/version-0.12/community/intro/_category_.json create mode 100644 versioned_docs/version-0.12/community/intro/intro.md create mode 100644 versioned_docs/version-0.12/community/intro/license.md create mode 100644 versioned_docs/version-0.12/community/intro/support.md create mode 100644 versioned_docs/version-0.12/community/release-policy/_category_.json create mode 100644 versioned_docs/version-0.12/community/release-policy/index.md create mode 100644 versioned_docs/version-0.12/community/release-policy/kcl.md create mode 100644 versioned_docs/version-0.12/community/release-policy/roadmap.md create mode 100644 versioned_docs/version-0.12/reference/_category_.json create mode 100644 versioned_docs/version-0.12/reference/cheatsheets/_category_.json create mode 100644 versioned_docs/version-0.12/reference/cheatsheets/index.md create mode 100644 versioned_docs/version-0.12/reference/lang/_category_.json create mode 100644 versioned_docs/version-0.12/reference/lang/codelab/_category_.json create mode 100644 versioned_docs/version-0.12/reference/lang/codelab/collaborative.md create mode 100644 versioned_docs/version-0.12/reference/lang/codelab/index.md create mode 100644 versioned_docs/version-0.12/reference/lang/codelab/schema.md create mode 100644 versioned_docs/version-0.12/reference/lang/codelab/simple.md create mode 100644 versioned_docs/version-0.12/reference/lang/error/_category_.json create mode 100644 versioned_docs/version-0.12/reference/lang/error/exception.md create mode 100644 versioned_docs/version-0.12/reference/lang/error/index.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/_category_.json create mode 100644 versioned_docs/version-0.12/reference/lang/spec/codestyle.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/datatypes.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/error.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/expressions.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/index.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/kcl-spec.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/lexical.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/modules.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/schema.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/statements.md create mode 100644 versioned_docs/version-0.12/reference/lang/spec/variables.md create mode 100644 versioned_docs/version-0.12/reference/lang/tour.md create mode 100644 versioned_docs/version-0.12/reference/lang/types/_category_.json create mode 100644 versioned_docs/version-0.12/reference/lang/types/types.md create mode 100644 versioned_docs/version-0.12/reference/model/_category_.json create mode 100644 versioned_docs/version-0.12/reference/model/base64.md create mode 100644 versioned_docs/version-0.12/reference/model/builtin.md create mode 100644 versioned_docs/version-0.12/reference/model/crypto.md create mode 100644 versioned_docs/version-0.12/reference/model/datetime.md create mode 100644 versioned_docs/version-0.12/reference/model/file.md create mode 100644 versioned_docs/version-0.12/reference/model/json.md create mode 100644 versioned_docs/version-0.12/reference/model/manifests.md create mode 100644 versioned_docs/version-0.12/reference/model/math.md create mode 100644 versioned_docs/version-0.12/reference/model/net.md create mode 100644 versioned_docs/version-0.12/reference/model/overview.md create mode 100644 versioned_docs/version-0.12/reference/model/regex.md create mode 100644 versioned_docs/version-0.12/reference/model/runtime.md create mode 100644 versioned_docs/version-0.12/reference/model/template.md create mode 100644 versioned_docs/version-0.12/reference/model/units.md create mode 100644 versioned_docs/version-0.12/reference/model/yaml.md create mode 100644 versioned_docs/version-0.12/reference/plugin/_category_.json create mode 100644 versioned_docs/version-0.12/reference/plugin/overview.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/_category_.json create mode 100644 versioned_docs/version-0.12/reference/xlang-api/c-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/cpp-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/dotnet-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/go-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/java-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/kotlin-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/lua-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/nodejs-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/overview.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/python-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/rest-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/rust-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/swift-api.md create mode 100644 versioned_docs/version-0.12/reference/xlang-api/wasm-api.md create mode 100644 versioned_docs/version-0.12/tools/Ide/_category_.json create mode 100644 versioned_docs/version-0.12/tools/Ide/index.md create mode 100644 versioned_docs/version-0.12/tools/Ide/intellij.md create mode 100644 versioned_docs/version-0.12/tools/Ide/neovim.md create mode 100644 versioned_docs/version-0.12/tools/Ide/vs-code.md create mode 100644 versioned_docs/version-0.12/tools/_category_.json create mode 100644 versioned_docs/version-0.12/tools/cli/_category_.json create mode 100644 versioned_docs/version-0.12/tools/cli/index.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/_category_.json create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/docgen.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/fmt.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/import.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/index.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/lint.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/overview.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/run.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/test.md create mode 100644 versioned_docs/version-0.12/tools/cli/kcl/vet.md create mode 100644 versioned_docs/version-0.12/tools/cli/openapi/_category_.json create mode 100644 versioned_docs/version-0.12/tools/cli/openapi/crd-to-kcl.md create mode 100644 versioned_docs/version-0.12/tools/cli/openapi/openapi-to-kcl.md create mode 100644 versioned_docs/version-0.12/tools/cli/openapi/spec.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/_category_.json create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/1.init.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/10.help.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/11.update.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/12.graph.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/2.add.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/3.pkg.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/4.metadata.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/6.login.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/7.logout.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/8.push.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/9.pull.md create mode 100644 versioned_docs/version-0.12/tools/cli/package-management/command-reference/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/concepts/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/concepts/concepts.md create mode 100644 versioned_docs/version-0.12/user_docs/concepts/package-and-module.md create mode 100644 versioned_docs/version-0.12/user_docs/concepts/type-and-definition.md create mode 100644 versioned_docs/version-0.12/user_docs/getting-started/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/getting-started/index.md create mode 100644 versioned_docs/version-0.12/user_docs/getting-started/install.md create mode 100644 versioned_docs/version-0.12/user_docs/getting-started/intro.md create mode 100644 versioned_docs/version-0.12/user_docs/getting-started/kcl-quick-start.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/abstraction.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/automation.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/ci-integration/1-github-actions.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/ci-integration/2-gitlab-ci.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/ci-integration/_3-jenkins-ci.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/ci-integration/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/configuration.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/data-integration.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/gitops/1-argocd.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/gitops/2-fluxcd.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/gitops/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/index.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/3-quick-start.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/10-kpm_git.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/4-share_your_pkg.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/5-share_your_pkg_docker.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/6-push_github_action.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/7-publish_pkg_to_ah.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/8-kcl_mod.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/9-kpm_oci.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/4-how-to/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/package-management/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/schema-definition.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/secret-management/1-vault.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/secret-management/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/validation.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/0-overview.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/1-adapt-from-kubernetes.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/2-generate-k8s-manifests.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/1-kubectl-kcl-plugin.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/2-helm-kcl-plugin.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/3-kustomize-kcl-plugin.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/4-kpt-kcl-sdk.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/5-helmfile-kcl-plugin.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/6-kcl-operator.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/7-crossplane-kcl-function.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-k8s/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-konfig/1-overview.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-konfig/2-structure.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-konfig/3-quick-start.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-konfig/4-best-practice.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-konfig/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-kubevela/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-kubevela/index.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-kusion/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-kusion/index.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-terraform/3-validation.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-terraform/_1-adapt-from-terraform.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-terraform/_2-abstraction.md create mode 100644 versioned_docs/version-0.12/user_docs/guides/working-with-terraform/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/support/_category_.json create mode 100644 versioned_docs/version-0.12/user_docs/support/faq-cli.md create mode 100644 versioned_docs/version-0.12/user_docs/support/faq-install.md create mode 100644 versioned_docs/version-0.12/user_docs/support/faq-kcl.md create mode 100644 versioned_docs/version-0.12/user_docs/support/faq-yaml.md create mode 100644 versioned_docs/version-0.12/user_docs/support/support.md create mode 100644 versioned_sidebars/version-0.12-sidebars.json diff --git a/.gitignore b/.gitignore index 973d3bdaa..af8bc2f98 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ yarn-error.log* .vscode/ .idea/ -.kclvm +.kcl .terraform .terraform.lock.hcl +pnpm-lock.yaml diff --git a/VERSION b/VERSION index 0eb41820e..f2bb2d0a2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11 \ No newline at end of file +0.12 \ No newline at end of file diff --git a/blog/2024-11-14-newsletter/index.md b/blog/2024-11-14-newsletter/index.md index f641e2b5d..30f6bd9eb 100644 --- a/blog/2024-11-14-newsletter/index.md +++ b/blog/2024-11-14-newsletter/index.md @@ -35,7 +35,7 @@ Thanks to all community participants over the past two weeks, listed in no parti - Supports hint for config entry key type - Optimized static analysis of unpacking expressions `**expr`, providing richer diagnostic information -- Optimized code snippet completion for schema types `{}` +- Optimized code snippet completion for schema types `{}` - Added monitoring for changes in `kcl.mod` files, improving external package completion experience - Differentiated highlight colors for `any` type and `any` keyword expressions diff --git a/blog/2024-12-24-kcl-0.11.0-release/index.md b/blog/2024-12-24-kcl-0.11.0-release/index.md index 2b25ba837..220c3e509 100644 --- a/blog/2024-12-24-kcl-0.11.0-release/index.md +++ b/blog/2024-12-24-kcl-0.11.0-release/index.md @@ -20,7 +20,7 @@ The KCL team is pleased to announce that **KCL v0.11.0 is now available**! This **We would like to extend our heartfelt thanks to all community contributors who participated in the iteration from version v0.10 to v0.11. The following list is in no particular order.** -_@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @eminaktas, @Gmin2, @tvandinther, @diefans, @nkabir, @suin, @Chewie, @lwz23, @eminaktas,@steeling, @bozaro, @cakemanny, @Yufeireal, @andrzejgorski, @yonas, @dansrogers, @SkySingh04, @jellllly420, @slashexx, @xnull, @diefans, @zflat, @vfarcic, @spastorclovr, @patpicos, @mproffitt, @fraenkel, @irizzant, @vfarcic, @patpicos, @mproffitt, @fraenkel, @Clint, @Christopher Haar, @ron18219, @Zack Zhang, @Alexander Fuchs, @Smaine Kahlouch, @Yvan da Silva, @Jakob Maležič, @Ryan Rueth, @Christopher Haar, @kesser, @Justin B, @Evgeny Shepelyuk, @Smaine Kahlouch, @KennyZ, @Mark Altmann (Wompi), @Peter Boat, @Hai Wu, @Evgeny Shepelyuk, @anshuman singh, @Carl-Fredrik, @Larry Gadallah, @Kevin Sztern, @Nick Atzert, @Tobias Kässer, @Mike, @john thompson, @Sky Singh, @suin, @Tom van Dinther, @Stefano Borrelli, @Valer Orlovsky, @Jacob Colvin, @Sjuul Janssen, @Vyacheslav Terdunov, @Yury Tsarev_ +_@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @eminaktas, @Gmin2, @tvandinther, @diefans, @nkabir, @suin, @Chewie, @lwz23, @eminaktas,@steeling, @bozaro, @cakemanny, @Yufeireal, @andrzejgorski, @yonas, @dansrogers, @SkySingh04, @jellllly420, @slashexx, @xnull, @diefans, @zflat, @vfarcic, @spastorclovr, @patpicos, @mproffitt, @fraenkel, @irizzant, @vfarcic, @patpicos, @mproffitt, @fraenkel, @Clint, @Christopher Haar, @ron18219, @Zack Zhang, @Alexander Fuchs, @Smaine Kahlouch, @Yvan da Silva, @Jakob Maležič, @Ryan Rueth, @Christopher Haar, @kesser, @Justin B, @Evgeny Shepelyuk, @Smaine Kahlouch, @KennyZ, @Mark Altmann (Wompi), @Peter Boat, @Hai Wu, @Evgeny Shepelyuk, @anshuman singh, @Carl-Fredrik, @Larry Gadallah, @Kevin Sztern, @Nick Atzert, @Tobias Kässer, @Mike, @john thompson, @Sky Singh, @suin, @Tom van Dinther, @Stefano Borrelli, @Valer Orlovsky, @Jacob Colvin, @Sjuul Janssen, @Vyacheslav Terdunov, @Yury Tsarev_ ## 📚 Key Updates @@ -30,16 +30,15 @@ _@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @emi - KCL supports Alpine Linux(musl) platform. - KCL refactored the implementation of the Parser and reorganized the parse process of import dependencies. -- KCL optimized the type parsing of ** expressions in schema attributes. +- KCL optimized the type parsing of \*\* expressions in schema attributes. - KCL fixed the problem that lambda expressions do not work when nested calls. - KCL fixed the memory leak problem of schema mixin parse. - KCL fixed the type promotion in function call expressions in assignment statements with type declarations. - KCL fixed the error of lambda functions calling attr in mixin - #### Toolchain -- Package management tool version selection algorithm is released. In v0.11.0, the KCL package management tool supports the selection of different version numbers of the same tripartite library that appears in the dependency graph. The KCL package management tool refers to the mvs algorithm of go mod. +- Package management tool version selection algorithm is released. In v0.11.0, the KCL package management tool supports the selection of different version numbers of the same tripartite library that appears in the dependency graph. The KCL package management tool refers to the mvs algorithm of go mod. To ensure as much compatibility as possible, package management tools currently prefer to select the latest version that appears in the dependency diagram rather than the latest version that has already been released. @@ -56,11 +55,11 @@ In v0.11.0, the new cache structure is turned off by default, and the new local - KCL IntelliJ plugin released 0.4.0, supporting LSP4IJ. - IDE can complete schemas defined in the worksace but not imported , and automatically insert the import statements of the package. -![complete](/img/blog/2024-12-06-kcl-0.11.0-release/complete.gif) + ![complete](/img/blog/2024-12-06-kcl-0.11.0-release/complete.gif) - IDE adds type hints for key in the Config block. -![hint](/img/blog/2024-12-06-kcl-0.11.0-release/hint.png) + ![hint](/img/blog/2024-12-06-kcl-0.11.0-release/hint.png) - IDE hover provides schema attribute default value information. -![hover](/img/blog/2024-12-06-kcl-0.11.0-release/hover.png) + ![hover](/img/blog/2024-12-06-kcl-0.11.0-release/hover.png) - IDE fixed the failure of Windows path issues. - IDE fixed the failure of compound assignment operation statements. - IDE distinguished the highlighting of the `any` from keyword and type. diff --git a/docs/reference/model/net.md b/docs/reference/model/net.md index 24b942b76..bcf09a47e 100644 --- a/docs/reference/model/net.md +++ b/docs/reference/model/net.md @@ -28,7 +28,7 @@ assert net.split_host_port("[::1]:80") == ["::1", "80"] `join_host_port(host: str, port: int | str) -> str` Combines `host` and `port` into a network address of the form `host:port`. -If `host` contains a colon, as found in an IPv6 address literal, then returns `[host]:port`. +If `host` contains a colon, as found in an IPv6 address literal, then returns `[host]:port`. ```python import net @@ -277,7 +277,7 @@ Calculates a subnet of the CIDR `cidr`. Extends the prefix of `cidr` by `additional_bits`. For example, if `cidr` is a `/18` and `additional_bits` is `6`, then the result will be a `/24`. -`net_num` is a non-negative number used to populate the bits added to the prefix. +`net_num` is a non-negative number used to populate the bits added to the prefix. ```python import net diff --git a/docs/reference/xlang-api/c-api.md b/docs/reference/xlang-api/c-api.md index 9d9afa6cc..7ffc812db 100644 --- a/docs/reference/xlang-api/c-api.md +++ b/docs/reference/xlang-api/c-api.md @@ -35,12 +35,12 @@ int exec_file(const char* file_str) { }; struct Buffer* files[] = { &file }; struct RepeatedString strs = { .repeated = &files[0], .index = 0, .max_size = 1 }; - ExecProgram_Args args = ExecProgram_Args_init_zero; + ExecProgramArgs args = ExecProgramArgs_init_zero; args.k_filename_list.funcs.encode = encode_str_list; args.k_filename_list.arg = &strs; pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - status = pb_encode(&stream, ExecProgram_Args_fields, &args); + status = pb_encode(&stream, ExecProgramArgs_fields, &args); message_length = stream.bytes_written; if (!status) { @@ -48,7 +48,7 @@ int exec_file(const char* file_str) { return 1; } - const char* api_str = "KclvmService.ExecProgram"; + const char* api_str = "KclService.ExecProgram"; size_t result_length = call_native((const uint8_t*)api_str, strlen(api_str), buffer, message_length, result_buffer); if (check_error_prefix(result_buffer)) { printf("%s", result_buffer); @@ -56,7 +56,7 @@ int exec_file(const char* file_str) { } pb_istream_t istream = pb_istream_from_buffer(result_buffer, result_length); - ExecProgram_Result result = ExecProgram_Result_init_default; + ExecProgramResult result = ExecProgramResult_init_default; uint8_t yaml_value_buffer[BUFFER_SIZE] = { 0 }; result.yaml_result.arg = yaml_value_buffer; @@ -74,7 +74,7 @@ int exec_file(const char* file_str) { result.log_message.arg = log_value_buffer; result.log_message.funcs.decode = decode_string; - status = pb_decode(&istream, ExecProgram_Result_fields, &result); + status = pb_decode(&istream, ExecProgramResult_fields, &result); if (!status) { printf("Decoding failed: %s\n", PB_GET_ERROR(&istream)); @@ -115,14 +115,14 @@ int validate(const char* code_str, const char* data_str) size_t message_length; bool status; - ValidateCode_Args validate_args = ValidateCode_Args_init_zero; + ValidateCodeArgs validate_args = ValidateCodeArgs_init_zero; validate_args.code.funcs.encode = encode_string; validate_args.code.arg = (void*)code_str; validate_args.data.funcs.encode = encode_string; validate_args.data.arg = (void*)data_str; pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - status = pb_encode(&stream, ValidateCode_Args_fields, &validate_args); + status = pb_encode(&stream, ValidateCodeArgs_fields, &validate_args); message_length = stream.bytes_written; if (!status) { @@ -130,16 +130,16 @@ int validate(const char* code_str, const char* data_str) return 1; } - const char* api_str = "KclvmService.ValidateCode"; + const char* api_str = "KclService.ValidateCode"; size_t result_length = call_native((const uint8_t*)api_str, strlen(api_str), buffer, message_length, result_buffer); pb_istream_t istream = pb_istream_from_buffer(result_buffer, result_length); - ValidateCode_Result result = ValidateCode_Result_init_default; + ValidateCodeResult result = ValidateCodeResult_init_default; result.err_message.funcs.decode = decode_string; uint8_t value_buffer[BUFFER_SIZE] = { 0 }; result.err_message.arg = value_buffer; - status = pb_decode(&istream, ValidateCode_Result_fields, &result); + status = pb_decode(&istream, ValidateCodeResult_fields, &result); if (!status) { printf("Decoding failed: %s\n", PB_GET_ERROR(&istream)); diff --git a/docs/reference/xlang-api/cpp-api.md b/docs/reference/xlang-api/cpp-api.md index 6e75ed921..f6235eabd 100644 --- a/docs/reference/xlang-api/cpp-api.md +++ b/docs/reference/xlang-api/cpp-api.md @@ -22,7 +22,7 @@ You can use FetchContent to add KCL C++ Lib to your project. FetchContent_Declare( kcl-lib GIT_REPOSITORY https://github.com/kcl-lang/lib.git - GIT_TAG v0.10.8 # You can change the GitHub branch tag. + GIT_TAG v0.12.1 # You can change the GitHub branch tag. SOURCE_SUBDIR cpp ) FetchContent_MakeAvailable(kcl-lib) diff --git a/docs/reference/xlang-api/dotnet-api.md b/docs/reference/xlang-api/dotnet-api.md index 50fdb70c2..de3bef296 100644 --- a/docs/reference/xlang-api/dotnet-api.md +++ b/docs/reference/xlang-api/dotnet-api.md @@ -16,7 +16,7 @@ dotnet add package KclLib using KclLib.API; var api = new API(); -var execArgs = new ExecProgram_Args(); +var execArgs = new ExecProgramArgs(); var path = Path.Combine("test_data", "schema.k"); execArgs.KFilenameList.Add(path); var result = api.ExecProgram(execArgs); @@ -48,7 +48,7 @@ C# Code ```csharp using KclLib.API; -var execArgs = new ExecProgram_Args(); +var execArgs = new ExecProgramArgs(); var path = "schema.k" execArgs.KFilenameList.Add(path); var result = new API().ExecProgram(execArgs); @@ -81,7 +81,7 @@ C# Code using KclLib.API; var path = "schema.k" -var args = new ParseFile_Args { Path = path }; +var args = new ParseFileArgs { Path = path }; var result = new API().ParseFile(args); ``` @@ -112,7 +112,7 @@ C# Code using KclLib.API; var path = "schema.k"; -var args = new ParseProgram_Args(); +var args = new ParseProgramArgs(); args.Paths.Add(path); var result = new API().ListOptions(args); ``` @@ -144,9 +144,9 @@ C# Code using KclLib.API; var path = "schema.k"; -var args = new LoadPackage_Args(); +var args = new LoadPackageArgs(); args.ResolveAst = true; -args.ParseArgs = new ParseProgram_Args(); +args.ParseArgs = new ParseProgramArgs(); args.ParseArgs.Paths.Add(path); var result = new API().LoadPackage(args); ``` @@ -178,7 +178,7 @@ C# Code using KclLib.API; var api = new API(); -var args = new ListVariables_Args(); +var args = new ListVariablesArgs(); var path = "schema.k"; args.Files.Add(path); var result = api.ListVariables(args); @@ -210,7 +210,7 @@ C# Code using KclLib.API; var path = "options.k"; -var args = new ParseProgram_Args(); +var args = new ParseProgramArgs(); args.Paths.Add(path); var result = new API().ListOptions(args); ``` @@ -242,9 +242,9 @@ C# Code using KclLib.API; var path = "schema.k"; -var execArgs = new ExecProgram_Args(); +var execArgs = new ExecProgramArgs(); execArgs.KFilenameList.Add(path); -var args = new GetSchemaTypeMapping_Args(); +var args = new GetSchemaTypeMappingArgs(); args.ExecArgs = execArgs; var result = new API().GetSchemaTypeMapping(args); ``` @@ -275,7 +275,7 @@ C# Code ```csharp using KclLib.API; -var args = new OverrideFile_Args +var args = new OverrideFileArgs { File = "main.k", }; @@ -303,7 +303,7 @@ string sourceCode = "schema Person:\n" + " name: str\n" + " age: int\ string expectedFormattedCode = "schema Person:\n" + " name: str\n" + " age: int\n\n" + " check:\n" + " 0 < age < 120\n\n"; var api = new API(); -var args = new FormatCode_Args(); +var args = new FormatCodeArgs(); args.Source = sourceCode; var result = api.FormatCode(args); ``` @@ -335,7 +335,7 @@ C# Code using KclLib.API; var api = new API(); -var args = new FormatPath_Args(); +var args = new FormatPathArgs(); var path = "format_path.k"; args.Path = path; var result = api.FormatPath(args); @@ -365,7 +365,7 @@ C# Code using KclLib.API; var path = "lint_path.k" -var args = new LintPath_Args(); +var args = new LintPathArgs(); args.Paths.Add(path); var result = new API().LintPath(args); bool foundWarning = result.Results.Any(warning => warning.Contains("Module 'math' imported but unused")); @@ -394,7 +394,7 @@ schema Person: 0 < age < 120 "; string data = "{\"name\": \"Alice\", \"age\": 10}"; -var args = new ValidateCode_Args +var args = new ValidateCodeArgs { Code = code, Data = data, @@ -425,10 +425,10 @@ C# Code ```csharp using KclLib.API; -Rename_Args args = Rename_Args.newBuilder().setPackageRoot(".").setSymbolPath("a") +RenameArgs args = RenameArgs.newBuilder().setPackageRoot(".").setSymbolPath("a") .addFilePaths("main.k").setNewName("a2").build(); API apiInstance = new API(); -Rename_Result result = apiInstance.rename(args); +RenameResult result = apiInstance.rename(args); ```

@@ -446,7 +446,7 @@ C# Code ```csharp using KclLib.API; -var args = new RenameCode_Args +var args = new RenameCodeArgs { PackageRoot = "/mock/path", SymbolPath = "a", @@ -472,7 +472,7 @@ C# Code using KclLib.API; var pkg = Path.Combine(parentDirectory, "test_data", "testing"); -var args = new Test_Args(); +var args = new TestArgs(); args.PkgList.Add(pkg + "/..."); var result = new API().Test(args); ``` @@ -504,7 +504,7 @@ using KclLib.API; var workDir = "."; var settingsFile = "kcl.yaml"; -var args = new LoadSettingsFiles_Args +var args = new LoadSettingsFilesArgs { WorkDir = workDir, }; @@ -541,7 +541,7 @@ C# Code using KclLib.API; var manifestPath = "module"; -var args = new UpdateDependencies_Args { ManifestPath = manifestPath }; +var args = new UpdateDependenciesArgs { ManifestPath = manifestPath }; var result = new API().UpdateDependencies(args); ``` @@ -584,9 +584,9 @@ API api = new API(); var manifestPath = "module"; var testFile = Path.Combine(manifestPath, "main.k"); -var updateArgs = new UpdateDependencies_Args { ManifestPath = manifestPath }; +var updateArgs = new UpdateDependenciesArgs { ManifestPath = manifestPath }; var depResult = new API().UpdateDependencies(updateArgs); -var execArgs = new ExecProgram_Args(); +var execArgs = new ExecProgramArgs(); execArgs.KFilenameList.Add(testFile); execArgs.ExternalPkgs.AddRange(depResult.ExternalPkgs); var execResult = new API().ExecProgram(execArgs); @@ -607,7 +607,7 @@ C# Code ```csharp using KclLib.API; -var result = new API().GetVersion(new GetVersion_Args()); +var result = new API().GetVersion(new GetVersionArgs()); ```

diff --git a/docs/reference/xlang-api/go-api.md b/docs/reference/xlang-api/go-api.md index 739bb18c2..3c255e38e 100644 --- a/docs/reference/xlang-api/go-api.md +++ b/docs/reference/xlang-api/go-api.md @@ -7,7 +7,7 @@ sidebar_position: 3 ```go -import kcl "kcl-lang.io/kcl-go" +import "kcl-lang.io/kcl-go" ``` ``` @@ -90,82 +90,16 @@ x1 = Person {

-## Index - -- [Go API](#go-api) - - [Index](#index) - - [Constants](#constants) - - [func FormatCode](#func-formatcode) - - [func FormatPath](#func-formatpath) - - [func GetSchemaTypeMapping](#func-getschematypemapping) - - [func InitKclvmPath](#func-initkclvmpath) - - [func InitKclvmRuntime](#func-initkclvmruntime) - - [func LintPath](#func-lintpath) - - [func ListDepFiles](#func-listdepfiles) - - [func ListDownStreamFiles](#func-listdownstreamfiles) - - [func ListUpStreamFiles](#func-listupstreamfiles) - - [func OverrideFile](#func-overridefile) - - [func Validate](#func-validate) - - [func ValidateCode](#func-validatecode) - - [type KCLResult](#type-kclresult) - - [type KCLResultList](#type-kclresultlist) - - [func MustRun](#func-mustrun) - - [func Run](#func-run) - - [func RunFiles](#func-runfiles) - - [type KclType](#type-kcltype) - - [func GetSchemaType](#func-getschematype) - - [type ListDepFilesOption](#type-listdepfilesoption) - - [type ListDepsOptions](#type-listdepsoptions) - - [type ListOptionsArgs](#type-listoptionsargs) - - [type ListOptionsResult](#type-listoptionsresult) - - [func ListOptions](#func-listoptions) - - [type ListVariablesArgs](#type-listvariablesargs) - - [type ListVariablesResult](#type-listvariablesresult) - - [func ListVariables](#func-listvariables) - - [type LoadPackageArgs](#type-loadpackageargs) - - [type LoadPackageResult](#type-loadpackageresult) - - [func LoadPackage](#func-loadpackage) - - [type Option](#type-option) - - [func NewOption](#func-newoption) - - [func WithCode](#func-withcode) - - [func WithDisableNone](#func-withdisablenone) - - [func WithExternalPkgAndPath](#func-withexternalpkgandpath) - - [func WithExternalPkgs](#func-withexternalpkgs) - - [func WithFullTypePath](#func-withfulltypepath) - - [func WithIncludeSchemaTypePath](#func-withincludeschematypepath) - - [func WithKFilenames](#func-withkfilenames) - - [func WithLogger](#func-withlogger) - - [func WithOptions](#func-withoptions) - - [func WithOverrides](#func-withoverrides) - - [func WithPrintOverridesAST](#func-withprintoverridesast) - - [func WithSelectors](#func-withselectors) - - [func WithSettings](#func-withsettings) - - [func WithShowHidden](#func-withshowhidden) - - [func WithSortKeys](#func-withsortkeys) - - [func WithWorkDir](#func-withworkdir) - - [type ParseProgramArgs](#type-parseprogramargs) - - [type ParseProgramResult](#type-parseprogramresult) - - [func ParseProgram](#func-parseprogram) - - [type TestCaseInfo](#type-testcaseinfo) - - [type TestOptions](#type-testoptions) - - [type TestResult](#type-testresult) - - [func Test](#func-test) - - [type UpdateDependenciesArgs](#type-updatedependenciesargs) - - [type UpdateDependenciesResult](#type-updatedependenciesresult) - - [func UpdateDependencies](#func-updatedependencies) - - [type ValidateOptions](#type-validateoptions) - - [type VersionResult](#type-versionresult) - - [func GetVersion](#func-getversion) ## Constants -KclvmAbiVersion is the current kclvm ABI version. +KclAbiVersion is the current kcl ABI version. ```go -const KclvmAbiVersion = scripts.KclvmAbiVersion +const KclAbiVersion = scripts.KclAbiVersion ``` -## func [FormatCode](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L167) +## func [FormatCode](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L156) ```go func FormatCode(code interface{}) ([]byte, error) @@ -203,7 +137,7 @@ a = 1 + 2

-## func [FormatPath](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L179) +## func [FormatPath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L168) ```go func FormatPath(path string) (changedPaths []string, err error) @@ -238,7 +172,7 @@ func main() {

-## func [GetSchemaTypeMapping](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L258) +## func [GetSchemaTypeMapping](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L247) ```go func GetSchemaTypeMapping(filename string, src any, schemaName string) (map[string]*KclType, error) @@ -264,23 +198,8 @@ schema_name: string The schema name got, when the schema name is empty, all schemas are returned. ``` -## func [InitKclvmPath](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L75) -```go -func InitKclvmPath(kclvmRoot string) -``` - -InitKclvmPath init kclvm path. - -## func [InitKclvmRuntime](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L80) - -```go -func InitKclvmRuntime(n int) -``` - -InitKclvmRuntime init kclvm process. - -## func [LintPath](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L199) +## func [LintPath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L188) ```go func LintPath(paths []string) (results []string, err error) @@ -325,7 +244,7 @@ Module 'a' imported but unused

-## func [ListDepFiles](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L184) +## func [ListDepFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L173) ```go func ListDepFiles(workDir string, opt *ListDepFilesOption) (files []string, err error) @@ -333,7 +252,7 @@ func ListDepFiles(workDir string, opt *ListDepFilesOption) (files []string, err ListDepFiles return the depend files from the given path -## func [ListDownStreamFiles](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L194) +## func [ListDownStreamFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L183) ```go func ListDownStreamFiles(workDir string, opt *ListDepsOptions) ([]string, error) @@ -341,7 +260,7 @@ func ListDownStreamFiles(workDir string, opt *ListDepsOptions) ([]string, error) ListDownStreamFiles return a list of downstream depend files from the given changed path list. -## func [ListUpStreamFiles](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L189) +## func [ListUpStreamFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L178) ```go func ListUpStreamFiles(workDir string, opt *ListDepsOptions) (deps []string, err error) @@ -349,7 +268,7 @@ func ListUpStreamFiles(workDir string, opt *ListDepsOptions) (deps []string, err ListUpStreamFiles return a list of upstream depend files from the given path list -## func [OverrideFile](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L208) +## func [OverrideFile](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L197) ```go func OverrideFile(file string, specs, importPaths []string) (bool, error) @@ -357,7 +276,7 @@ func OverrideFile(file string, specs, importPaths []string) (bool, error) OverrideFile rewrites a file with override spec file: string. The File that need to be overridden specs: \[\]string. List of specs that need to be overridden. importPaths. List of import statements that need to be added. See https://www.kcl-lang.io/docs/user_docs/guides/automation for more override spec guide. -## func [Validate](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L219) +## func [Validate](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L208) ```go func Validate(dataFile, schemaFile string, opts *ValidateOptions) (ok bool, err error) @@ -365,7 +284,7 @@ func Validate(dataFile, schemaFile string, opts *ValidateOptions) (ok bool, err Validate validates the given data file against the specified schema file with the provided options. -## func [ValidateCode](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L213) +## func [ValidateCode](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L202) ```go func ValidateCode(data, code string, opts *ValidateOptions) (ok bool, err error) @@ -373,7 +292,7 @@ func ValidateCode(data, code string, opts *ValidateOptions) (ok bool, err error) ValidateCode validate data string match code string -## type [KCLResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L57) +## type [KCLResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L56) ```go type KCLResult = kcl.KCLResult @@ -467,13 +386,13 @@ person: {Name:kcl Age:101}

-## type [KCLResultList](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L58) +## type [KCLResultList](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L57) ```go type KCLResultList = kcl.KCLResultList ``` -### func [MustRun](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L85) +### func [MustRun](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L74) ```go func MustRun(path string, opts ...Option) *KCLResultList @@ -600,7 +519,7 @@ func main() {

-### func [Run](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L90) +### func [Run](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L79) ```go func Run(path string, opts ...Option) (*KCLResultList, error) @@ -608,7 +527,7 @@ func Run(path string, opts ...Option) (*KCLResultList, error) Run evaluates the KCL program with path and opts, then returns the object list. -### func [RunFiles](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L95) +### func [RunFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L84) ```go func RunFiles(paths []string, opts ...Option) (*KCLResultList, error) @@ -637,13 +556,13 @@ func main() {

-## type [KclType](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L60) +## type [KclType](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L59) ```go type KclType = kcl.KclType ``` -### func [GetSchemaType](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L241) +### func [GetSchemaType](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L230) ```go func GetSchemaType(filename string, src any, schemaName string) ([]*KclType, error) @@ -669,31 +588,31 @@ schema_name: string The schema name got, when the schema name is empty, all schemas are returned. ``` -## type [ListDepFilesOption](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L52) +## type [ListDepFilesOption](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L51) ```go type ListDepFilesOption = list.Option ``` -## type [ListDepsOptions](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L51) +## type [ListDepsOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L50) ```go type ListDepsOptions = list.DepOptions ``` -## type [ListOptionsArgs](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L68) +## type [ListOptionsArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L67) ```go type ListOptionsArgs = loader.ListOptionsArgs ``` -## type [ListOptionsResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L69) +## type [ListOptionsResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L68) ```go type ListOptionsResult = loader.ListOptionsResult ``` -### func [ListOptions](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L280) +### func [ListOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L269) ```go func ListOptions(args *ListOptionsArgs) (*ListOptionsResult, error) @@ -722,30 +641,25 @@ func main() { log.Fatal(err) } fmt.Println(result) - } ``` -``` -options:{name:"key1"} options:{name:"key2" required:true} options:{name:"metadata-key"} -``` -

-## type [ListVariablesArgs](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L66) +## type [ListVariablesArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L65) ```go type ListVariablesArgs = loader.ListVariablesArgs ``` -## type [ListVariablesResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L67) +## type [ListVariablesResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L66) ```go type ListVariablesResult = loader.ListVariablesResult ``` -### func [ListVariables](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L274) +### func [ListVariables](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L263) ```go func ListVariables(args *ListVariablesArgs) (*ListVariablesResult, error) @@ -774,7 +688,6 @@ func main() { log.Fatal(err) } fmt.Println(result) - } ``` @@ -785,19 +698,19 @@ variables:{key:"age" value:{variables:{value:"2" op_sym:"="}}} variables:{key

-## type [LoadPackageArgs](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L64) +## type [LoadPackageArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L63) ```go type LoadPackageArgs = loader.LoadPackageArgs ``` -## type [LoadPackageResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L65) +## type [LoadPackageResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L64) ```go type LoadPackageResult = loader.LoadPackageResult ``` -### func [LoadPackage](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L269) +### func [LoadPackage](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L258) ```go func LoadPackage(args *LoadPackageArgs) (*LoadPackageResult, error) @@ -835,13 +748,13 @@ func main() {

-## type [Option](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L50) +## type [Option](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L49) ```go type Option = kcl.Option ``` -### func [NewOption](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L100) +### func [NewOption](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L89) ```go func NewOption() *Option @@ -849,7 +762,7 @@ func NewOption() *Option NewOption returns a new Option. -### func [WithCode](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L105) +### func [WithCode](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L94) ```go func WithCode(codes ...string) Option @@ -857,7 +770,7 @@ func WithCode(codes ...string) Option WithCode returns a Option which hold a kcl source code list. -### func [WithDisableNone](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L134) +### func [WithDisableNone](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L123) ```go func WithDisableNone(disableNone bool) Option @@ -865,7 +778,7 @@ func WithDisableNone(disableNone bool) Option WithDisableNone returns a Option which hold a disable none switch. -### func [WithExternalPkgAndPath](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L111) +### func [WithExternalPkgAndPath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L100) ```go func WithExternalPkgAndPath(name, path string) Option @@ -873,7 +786,7 @@ func WithExternalPkgAndPath(name, path string) Option WithExternalPkgAndPath returns a Option which hold a external package. -### func [WithExternalPkgs](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L108) +### func [WithExternalPkgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L97) ```go func WithExternalPkgs(externalPkgs ...string) Option @@ -881,7 +794,7 @@ func WithExternalPkgs(externalPkgs ...string) Option WithExternalPkgs returns a Option which hold a external package list. -### func [WithFullTypePath](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L142) +### func [WithFullTypePath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L131) ```go func WithFullTypePath(fullTypePath bool) Option @@ -889,7 +802,7 @@ func WithFullTypePath(fullTypePath bool) Option WithFullTypePath returns a Option which hold a include full type string in the \`\_type\` attribute. -### func [WithIncludeSchemaTypePath](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L137) +### func [WithIncludeSchemaTypePath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L126) ```go func WithIncludeSchemaTypePath(includeSchemaTypePath bool) Option @@ -897,7 +810,7 @@ func WithIncludeSchemaTypePath(includeSchemaTypePath bool) Option WithIncludeSchemaTypePath returns a Option which hold a include schema type path switch. -### func [WithKFilenames](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L116) +### func [WithKFilenames](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L105) ```go func WithKFilenames(filenames ...string) Option @@ -905,7 +818,7 @@ func WithKFilenames(filenames ...string) Option WithKFilenames returns a Option which hold a filenames list. -### func [WithLogger](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L162) +### func [WithLogger](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L151) ```go func WithLogger(l io.Writer) Option @@ -913,7 +826,7 @@ func WithLogger(l io.Writer) Option WithLogger returns a Option which hold a logger. -### func [WithOptions](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L119) +### func [WithOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L108) ```go func WithOptions(key_value_list ...string) Option @@ -959,7 +872,7 @@ name: kcl

-### func [WithOverrides](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L122) +### func [WithOverrides](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L111) ```go func WithOverrides(override_list ...string) Option @@ -967,7 +880,7 @@ func WithOverrides(override_list ...string) Option WithOverrides returns a Option which hold a override list. -### func [WithPrintOverridesAST](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L147) +### func [WithPrintOverridesAST](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L136) ```go func WithPrintOverridesAST(printOverridesAST bool) Option @@ -975,7 +888,7 @@ func WithPrintOverridesAST(printOverridesAST bool) Option WithPrintOverridesAST returns a Option which hold a printOverridesAST switch. -### func [WithSelectors](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L125) +### func [WithSelectors](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L114) ```go func WithSelectors(selectors ...string) Option @@ -983,7 +896,7 @@ func WithSelectors(selectors ...string) Option WithSelectors returns a Option which hold a path selector list. -### func [WithSettings](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L128) +### func [WithSettings](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L117) ```go func WithSettings(filename string) Option @@ -991,7 +904,7 @@ func WithSettings(filename string) Option WithSettings returns a Option which hold a settings file. -### func [WithShowHidden](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L157) +### func [WithShowHidden](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L146) ```go func WithShowHidden(showHidden bool) Option @@ -999,7 +912,7 @@ func WithShowHidden(showHidden bool) Option WithShowHidden returns a Option which holds a showHidden switch. -### func [WithSortKeys](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L152) +### func [WithSortKeys](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L141) ```go func WithSortKeys(sortKeys bool) Option @@ -1007,7 +920,7 @@ func WithSortKeys(sortKeys bool) Option WithSortKeys returns a Option which holds a sortKeys switch. -### func [WithWorkDir](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L131) +### func [WithWorkDir](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L120) ```go func WithWorkDir(workDir string) Option @@ -1015,19 +928,19 @@ func WithWorkDir(workDir string) Option WithWorkDir returns a Option which hold a work dir. -## type [ParseProgramArgs](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L70) +## type [ParseProgramArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L69) ```go type ParseProgramArgs = parser.ParseProgramArgs ``` -## type [ParseProgramResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L71) +## type [ParseProgramResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L70) ```go type ParseProgramResult = parser.ParseProgramResult ``` -### func [ParseProgram](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L263) +### func [ParseProgram](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L252) ```go func ParseProgram(args *ParseProgramArgs) (*ParseProgramResult, error) @@ -1062,25 +975,25 @@ func main() {

-## type [TestCaseInfo](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L55) +## type [TestCaseInfo](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L54) ```go type TestCaseInfo = testing.TestCaseInfo ``` -## type [TestOptions](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L54) +## type [TestOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L53) ```go type TestOptions = testing.TestOptions ``` -## type [TestResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L56) +## type [TestResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L55) ```go type TestResult = testing.TestResult ``` -### func [Test](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L224) +### func [Test](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L213) ```go func Test(testOpts *TestOptions, opts ...Option) (TestResult, error) @@ -1088,19 +1001,19 @@ func Test(testOpts *TestOptions, opts ...Option) (TestResult, error) Test calls the test tool to run uni tests in packages. -## type [UpdateDependenciesArgs](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L62) +## type [UpdateDependenciesArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L61) ```go type UpdateDependenciesArgs = module.UpdateDependenciesArgs ``` -## type [UpdateDependenciesResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L63) +## type [UpdateDependenciesResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L62) ```go type UpdateDependenciesResult = module.UpdateDependenciesResult ``` -### func [UpdateDependencies](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L285) +### func [UpdateDependencies](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L274) ```go func UpdateDependencies(args *UpdateDependenciesArgs) (*UpdateDependenciesResult, error) @@ -1132,7 +1045,7 @@ func main() { // helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } // flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } - result, err := kcl.UpdateDependencies(&gpyrpc.UpdateDependencies_Args{ + result, err := kcl.UpdateDependencies(&gpyrpc.UpdateDependenciesArgs{ ManifestPath: "testdata/update_dependencies", }) if err != nil { @@ -1156,7 +1069,7 @@ import ( "fmt" "log" - kcl "kcl-lang.io/kcl-go" + "kcl-lang.io/kcl-go/pkg/native" "kcl-lang.io/kcl-go/pkg/spec/gpyrpc" ) @@ -1170,7 +1083,9 @@ func main() { // helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } // flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } - result, err := kcl.UpdateDependencies(&gpyrpc.UpdateDependencies_Args{ + svc := native.NewNativeServiceClient() + + result, err := svc.UpdateDependencies(&gpyrpc.UpdateDependenciesArgs{ ManifestPath: "testdata/update_dependencies", }) if err != nil { @@ -1182,15 +1097,15 @@ func main() { // a = helloworld.The_first_kcl_program // fmt.Println(result.ExternalPkgs) - opt := kcl.NewOption() - opt.ExternalPkgs = result.ExternalPkgs - - runResult, err := kcl.Run("testdata/update_dependencies/main.k", *opt) + execResult, err := svc.ExecProgram(&gpyrpc.ExecProgramArgs{ + KFilenameList: []string{"testdata/update_dependencies/main.k"}, + ExternalPkgs: result.ExternalPkgs, + }) if err != nil { log.Fatal(err) } - fmt.Println(runResult.GetRawYamlResult()) + fmt.Println(execResult.YamlResult) } ``` @@ -1202,19 +1117,19 @@ a: Hello World!

-## type [ValidateOptions](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L53) +## type [ValidateOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L52) ```go type ValidateOptions = validate.ValidateOptions ``` -## type [VersionResult](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L61) +## type [VersionResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L60) ```go type VersionResult = kcl.VersionResult ``` -### func [GetVersion](https://github.com/kcl-lang/kcl-go/blob/main/kclvm.go#L290) +### func [GetVersion](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L279) ```go func GetVersion() (*VersionResult, error) diff --git a/docs/reference/xlang-api/java-api.md b/docs/reference/xlang-api/java-api.md index f7bc34633..f7d24658a 100644 --- a/docs/reference/xlang-api/java-api.md +++ b/docs/reference/xlang-api/java-api.md @@ -30,7 +30,7 @@ This way you'll be able to import the above dependency to use the SDK. com.kcl kcl-lib - 0.10.8-SNAPSHOT + 0.12.1 ``` @@ -38,14 +38,14 @@ This way you'll be able to import the above dependency to use the SDK. ```java import com.kcl.api.API; -import com.kcl.api.Spec.ExecProgram_Args; -import com.kcl.api.Spec.ExecProgram_Result; +import com.kcl.api.Spec.ExecProgramArgs; +import com.kcl.api.Spec.ExecProgramResult; public class ExecProgramTest { public static void main(String[] args) throws Exception { API api = new API(); - ExecProgram_Result result = api - .execProgram(ExecProgram_Args.newBuilder().addKFilenameList("path/to/kcl.k").build()); + ExecProgramResult result = api + .execProgram(ExecProgramArgs.newBuilder().addKFilenameList("path/to/kcl.k").build()); System.out.println(result.getYamlResult()); } } @@ -76,9 +76,9 @@ Java Code ```java import com.kcl.api.*; -ExecProgram_Args args = ExecProgram_Args.newBuilder().addKFilenameList("schema.k").build(); +ExecProgramArgs args = ExecProgramArgs.newBuilder().addKFilenameList("schema.k").build(); API apiInstance = new API(); -ExecProgram_Result result = apiInstance.execProgram(args); +ExecProgramResult result = apiInstance.execProgram(args); ```

@@ -107,9 +107,9 @@ Java Code ```java import com.kcl.api.*; -ParseFile_Args args = ParseFile_Args.newBuilder().setPath("schema.k").build(); +ParseFileArgs args = ParseFileArgs.newBuilder().setPath("schema.k").build(); API apiInstance = new API(); -ParseFile_Result result = apiInstance.parseFile(args); +ParseFileResult result = apiInstance.parseFile(args); ```

@@ -141,8 +141,8 @@ import com.kcl.ast.*; import com.kcl.util.JsonUtil; API api = new API(); -ParseProgram_Result result = api.parseProgram( - ParseProgram_Args.newBuilder().addPaths("path/to/kcl.k").build() +ParseProgramResult result = api.parseProgram( + ParseProgramArgs.newBuilder().addPaths("path/to/kcl.k").build() ); System.out.println(result.getAstJson()); Program program = JsonUtil.deserializeProgram(result.getAstJson()); @@ -175,9 +175,9 @@ Java Code import com.kcl.api.*; API api = new API(); -LoadPackage_Result result = api.loadPackage(LoadPackage_Args.newBuilder().setResolveAst(true) +LoadPackageResult result = api.loadPackage(LoadPackageArgs.newBuilder().setResolveAst(true) .setWithAstIndex(true) - .setParseArgs(ParseProgram_Args.newBuilder().addPaths("schema.k").build()).build()); + .setParseArgs(ParseProgramArgs.newBuilder().addPaths("schema.k").build()).build()); ```

@@ -207,9 +207,9 @@ Java Code import com.kcl.api.*; API api = new API(); -ListVariables_Result result = api.listVariables( - ListVariables_Args.newBuilder().setResolveAst(true).setParseArgs( - ParseProgram_Args.newBuilder().addPaths("/path/to/kcl.k").build()) +ListVariablesResult result = api.listVariables( + ListVariablesArgs.newBuilder().setResolveAst(true).setParseArgs( + ParseProgramArgs.newBuilder().addPaths("/path/to/kcl.k").build()) .build()); result.getSymbolsMap().values().forEach(s -> System.out.println(s)); ``` @@ -239,9 +239,9 @@ Java Code ```java import com.kcl.api.*; -ParseProgram_Args args = ParseProgram_Args.newBuilder().addPaths("./src/test_data/option/main.k").build(); +ParseProgramArgs args = ParseProgramArgs.newBuilder().addPaths("./src/test_data/option/main.k").build(); API apiInstance = new API(); -ListOptions_Result result = apiInstance.listOptions(args); +ListOptionsResult result = apiInstance.listOptions(args); ```

@@ -270,10 +270,10 @@ Java Code ```java import com.kcl.api.*; -ExecProgram_Args execArgs = ExecProgram_Args.newBuilder().addKFilenameList("schema.k").build(); -GetSchemaTypeMapping_Args args = GetSchemaTypeMapping_Args.newBuilder().setExecArgs(execArgs).build(); +ExecProgramArgs execArgs = ExecProgramArgs.newBuilder().addKFilenameList("schema.k").build(); +GetSchemaTypeMappingArgs args = GetSchemaTypeMappingArgs.newBuilder().setExecArgs(execArgs).build(); API apiInstance = new API(); -GetSchemaTypeMapping_Result result = apiInstance.getSchemaTypeMapping(args); +GetSchemaTypeMappingResult result = apiInstance.getSchemaTypeMapping(args); KclType appSchemaType = result.getSchemaTypeMappingMap().get("app"); String replicasType = appSchemaType.getPropertiesOrThrow("replicas").getType(); ``` @@ -306,7 +306,7 @@ import com.kcl.api.*; API api = new API(); String spec = "a=2"; -OverrideFile_Result result = api.overrideFile(OverrideFile_Args.newBuilder() +OverrideFileResult result = api.overrideFile(OverrideFileArgs.newBuilder() .setFile("./src/test_data/override_file/main.k").addSpecs(spec).build()); ``` @@ -327,9 +327,9 @@ import com.kcl.api.*; String sourceCode = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + " 0 < age < 120\n"; -FormatCode_Args args = FormatCode_Args.newBuilder().setSource(sourceCode).build(); +FormatCodeArgs args = FormatCodeArgs.newBuilder().setSource(sourceCode).build(); API apiInstance = new API(); -FormatCode_Result result = apiInstance.formatCode(args); +FormatCodeResult result = apiInstance.formatCode(args); String expectedFormattedCode = "schema Person:\n" + " name: str\n" + " age: int\n\n" + " check:\n" + " 0 < age < 120\n\n"; ``` @@ -360,9 +360,9 @@ Java Code ```java import com.kcl.api.*; -FormatPath_Args args = FormatPath_Args.newBuilder().setPath("format_path.k").build(); +FormatPathArgs args = FormatPathArgs.newBuilder().setPath("format_path.k").build(); API apiInstance = new API(); -FormatPath_Result result = apiInstance.formatPath(args); +FormatPathResult result = apiInstance.formatPath(args); Assert.assertTrue(result.getChangedPathsList().isEmpty()); ``` @@ -389,9 +389,9 @@ Java Code ```java import com.kcl.api.*; -LintPath_Args args = LintPath_Args.newBuilder().addPaths("lint_path.k").build(); +LintPathArgs args = LintPathArgs.newBuilder().addPaths("lint_path.k").build(); API apiInstance = new API(); -LintPath_Result result = apiInstance.lintPath(args); +LintPathResult result = apiInstance.lintPath(args); boolean foundWarning = result.getResultsList().stream() .anyMatch(warning -> warning.contains("Module 'math' imported but unused")); ``` @@ -414,9 +414,9 @@ import com.kcl.api.*; String code = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + " 0 < age < 120\n"; String data = "{\"name\": \"Alice\", \"age\": 10}"; -ValidateCode_Args args = ValidateCode_Args.newBuilder().setCode(code).setData(data).setFormat("json").build(); +ValidateCodeArgs args = ValidateCodeArgs.newBuilder().setCode(code).setData(data).setFormat("json").build(); API apiInstance = new API(); -ValidateCode_Result result = apiInstance.validateCode(args); +ValidateCodeResult result = apiInstance.validateCode(args); ```

@@ -441,10 +441,10 @@ Java Code ```java import com.kcl.api.*; -Rename_Args args = Rename_Args.newBuilder().setPackageRoot(".").setSymbolPath("a") +RenameArgs args = RenameArgs.newBuilder().setPackageRoot(".").setSymbolPath("a") .addFilePaths("main.k").setNewName("a2").build(); API apiInstance = new API(); -Rename_Result result = apiInstance.rename(args); +RenameResult result = apiInstance.rename(args); ```

@@ -463,9 +463,9 @@ Java Code import com.kcl.api.*; API api = new API(); -RenameCode_Args args = RenameCode_Args.newBuilder().setPackageRoot("/mock/path").setSymbolPath("a") +RenameCodeArgs args = RenameCodeArgs.newBuilder().setPackageRoot("/mock/path").setSymbolPath("a") .putSourceCodes("/mock/path/main.k", "a = 1\nb = a").setNewName("a2").build(); -RenameCode_Result result = api.renameCode(args); +RenameCodeResult result = api.renameCode(args); ```

@@ -484,8 +484,8 @@ Java Code import com.kcl.api.*; API apiInstance = new API(); -Test_Args args = Test_Args.newBuilder().addPkgList("/path/to/test/package").build(); -Test_Result result = apiInstance.test(args); +TestArgs args = TestArgs.newBuilder().addPkgList("/path/to/test/package").build(); +TestResult result = apiInstance.test(args); ```

@@ -514,9 +514,9 @@ Java Code import com.kcl.api.*; API api = new API(); -LoadSettingsFiles_Args args = LoadSettingsFiles_Args.newBuilder().addFiles("kcl.yaml") +LoadSettingsFilesArgs args = LoadSettingsFilesArgs.newBuilder().addFiles("kcl.yaml") .build(); -LoadSettingsFiles_Result result = api.loadSettingsFiles(args); +LoadSettingsFilesResult result = api.loadSettingsFiles(args); ```

@@ -549,8 +549,8 @@ import com.kcl.api.*; API api = new API(); -UpdateDependencies_Result result = api.updateDependencies( - UpdateDependencies_Args.newBuilder().setManifestPath("module").build()); +UpdateDependenciesResult result = api.updateDependencies( + UpdateDependenciesArgs.newBuilder().setManifestPath("module").build()); ```

@@ -590,13 +590,13 @@ import com.kcl.api.*; API api = new API(); -UpdateDependencies_Result result = api.updateDependencies( - UpdateDependencies_Args.newBuilder().setManifestPath("./src/test_data/update_dependencies").build()); +UpdateDependenciesResult result = api.updateDependencies( + UpdateDependenciesArgs.newBuilder().setManifestPath("./src/test_data/update_dependencies").build()); -ExecProgram_Args execArgs = ExecProgram_Args.newBuilder(). addAllExternalPkgs(result.getExternalPkgsList()) +ExecProgramArgs execArgs = ExecProgramArgs.newBuilder(). addAllExternalPkgs(result.getExternalPkgsList()) .addKFilenameList("./src/test_data/update_dependencies/main.k").build(); -ExecProgram_Result execResult = api.execProgram(execArgs); +ExecProgramResult execResult = api.execProgram(execArgs); ```

@@ -615,8 +615,8 @@ Java Code import com.kcl.api.*; API api = new API(); -GetVersion_Args version_args = GetVersion_Args.newBuilder().build(); -GetVersion_Result result = api.getVersion(version_args); +GetVersionArgs version_args = GetVersionArgs.newBuilder().build(); +GetVersionResult result = api.getVersion(version_args); ```

diff --git a/docs/reference/xlang-api/kotlin-api.md b/docs/reference/xlang-api/kotlin-api.md index c418127f7..4403b1097 100644 --- a/docs/reference/xlang-api/kotlin-api.md +++ b/docs/reference/xlang-api/kotlin-api.md @@ -30,7 +30,7 @@ This way you'll be able to import the above dependency to use the SDK. com.kcl kcl-lib-kotlin - 0.10.8-SNAPSHOT + 0.12.1 ``` diff --git a/docs/reference/xlang-api/overview.md b/docs/reference/xlang-api/overview.md index 21cbfb736..8ce491ae2 100644 --- a/docs/reference/xlang-api/overview.md +++ b/docs/reference/xlang-api/overview.md @@ -47,30 +47,30 @@ The complete `BuiltinService` is defined by Protobuf: ```protobuf service BuiltinService { - rpc Ping(Ping_Args) returns(Ping_Result); - rpc ListMethod(ListMethod_Args) returns(ListMethod_Result); + rpc Ping(PingArgs) returns(PingResult); + rpc ListMethod(ListMethodArgs) returns(ListMethodResult); } -message Ping_Args { +message PingArgs { string value = 1; } -message Ping_Result { +message PingResult { string value = 1; } -message ListMethod_Args { +message ListMethodArgs { // empty } -message ListMethod_Result { +message ListMethodResult { repeated string method_name_list = 1; } ``` The `Ping` method can verify whether the service is normal, and the `ListMethod` method can query the list of all services and functions provided. -### `KclvmService` +### `KclService` -The `KclvmService` service is a service related to KCL functionality. The usage is the same as the `BuiltinService` service. +The `KclService` service is a service related to KCL functionality. The usage is the same as the `BuiltinService` service. For example, there is the following `Person` structure definition: @@ -88,10 +88,10 @@ Then we want to use `Person` to verify the following JSON data: { "key": "value" } ``` -This can be done through the `ValidateCode` method of the `KclvmService` service. Refer to the `ValidateCode_Args` structure of the `ValidateCode` method: +This can be done through the `ValidateCode` method of the `KclService` service. Refer to the `ValidateCodeArgs` structure of the `ValidateCode` method: ```protobuf -message ValidateCode_Args { +message ValidateCodeArgs { string data = 1; string code = 2; string schema = 3; @@ -100,7 +100,7 @@ message ValidateCode_Args { } ``` -Construct the JSON data required by the POST request according to the `ValidateCode_Args` structure, which contains the `Person` definition and the JSON data to be verified: +Construct the JSON data required by the POST request according to the `ValidateCodeArgs` structure, which contains the `Person` definition and the JSON data to be verified: ```json { @@ -113,7 +113,7 @@ Save this JSON data to the `vet-hello.json` file and verify it with the followin ```shell $ curl -X POST \ - http://127.0.0.1:2021/api:protorpc/KclvmService.ValidateCode \ + http://127.0.0.1:2021/api:protorpc/KclService.ValidateCode \ -H "accept: application/json" \ --data @./vet-hello.json { diff --git a/docs/reference/xlang-api/python-api.md b/docs/reference/xlang-api/python-api.md index 5137d13f7..c8d7064ad 100644 --- a/docs/reference/xlang-api/python-api.md +++ b/docs/reference/xlang-api/python-api.md @@ -15,7 +15,7 @@ python3 -m pip install kcl-lib ```typescript import kcl_lib.api as api -args = api.ExecProgram_Args(k_filename_list=["path/to/kcl.k"]) +args = api.ExecProgramArgs(k_filename_list=["path/to/kcl.k"]) api = api.API() result = api.exec_program(args) print(result.yaml_result) @@ -46,7 +46,7 @@ Python Code ```python import kcl_lib.api as api -args = api.ExecProgram_Args(k_filename_list=["schema.k"]) +args = api.ExecProgramArgs(k_filename_list=["schema.k"]) api = api.API() result = api.exec_program(args) assert result.yaml_result == "app:\n replicas: 2" @@ -64,7 +64,7 @@ A case with the file not found error import kcl_lib.api as api try: - args = api.ExecProgram_Args(k_filename_list=["file_not_found"]) + args = api.ExecProgramArgs(k_filename_list=["file_not_found"]) api = api.API() result = api.exec_program(args) assert False @@ -98,7 +98,7 @@ Python Code ```python import kcl_lib.api as api -args = api.ParseFile_Args(path=TEST_FILE) +args = api.ParseFileArgs(path=TEST_FILE) api = api.API() result = api.parse_file(args) assert len(result.errors) == 0 @@ -130,7 +130,7 @@ Python Code ```python import kcl_lib.api as api -args = api.ParseProgram_Args(paths=["schema.k"]) +args = api.ParseProgramArgs(paths=["schema.k"]) api = api.API() result = api.parse_program(args) assert len(result.paths) == 1 @@ -163,8 +163,8 @@ Python Code ```python import kcl_lib.api as api -args = api.LoadPackage_Args( - parse_args=api.ParseProgram_Args(paths=["schema.k"]), resolve_ast=True +args = api.LoadPackageArgs( + parse_args=api.ParseProgramArgs(paths=["schema.k"]), resolve_ast=True ) api = api.API() result = api.load_package(args) @@ -197,7 +197,7 @@ Python Code ```python import kcl_lib.api as api -args = api.ListVariables_Args(files=[TEST_FILE]) +args = api.ListVariablesArgs(files=[TEST_FILE]) api = api.API() result = api.list_variables(args) assert result.variables["app"].variables[0].value == "AppConfig {replicas: 2}" @@ -228,7 +228,7 @@ Python Code ```python import kcl_lib.api as api -args = api.ParseProgram_Args(paths=["options.k"]) +args = api.ParseProgramArgs(paths=["options.k"]) api = api.API() result = api.list_options(args) assert len(result.options) == 3 @@ -263,8 +263,8 @@ Python Code ```python import kcl_lib.api as api -exec_args = api.ExecProgram_Args(k_filename_list=["schema.k"]) -args = api.GetSchemaTypeMapping_Args(exec_args=exec_args) +exec_args = api.ExecProgramArgs(k_filename_list=["schema.k"]) +args = api.GetSchemaTypeMappingArgs(exec_args=exec_args) api = api.API() result = api.get_schema_type_mapping(args) assert result.schema_type_mapping["app"].properties["replicas"].type == "int" @@ -298,7 +298,7 @@ import kcl_lib.api as api import pathlib test_file = "main.k" -args = api.OverrideFile_Args( +args = api.OverrideFileArgs( file=test_file, specs=["b.a=2"], ) @@ -338,7 +338,7 @@ schema Person: check: 0 < age < 120 """ -args = api.FormatCode_Args(source=source_code) +args = api.FormatCodeArgs(source=source_code) api_instance = api.API() result = api_instance.format_code(args) assert ( @@ -381,7 +381,7 @@ Python Code ```python import kcl_lib.api as api -args = api.FormatPath_Args(path="format_path.k") +args = api.FormatPathArgs(path="format_path.k") api_instance = api.API() result = api_instance.format_path(args) print(result) @@ -410,7 +410,7 @@ Python Code ```python import kcl_lib.api as api -args = api.LintPath_Args(paths=["lint_path.k"]) +args = api.LintPathArgs(paths=["lint_path.k"]) api_instance = api.API() result = api_instance.lint_path(args) ``` @@ -439,7 +439,7 @@ schema Person: 0 < age < 120 """ data = '{"name": "Alice", "age": 10}' -args = api.ValidateCode_Args(code=code, data=data, format="json") +args = api.ValidateCodeArgs(code=code, data=data, format="json") api_instance = api.API() result = api_instance.validate_code(args) assert result.success == True @@ -468,7 +468,7 @@ Python Code ```python import kcl_lib.api as api -args = api.Rename_Args( +args = api.RenameArgs( package_root=".", symbol_path="a", file_paths=["main.k"], @@ -493,7 +493,7 @@ Python Code ```python import kcl_lib.api as api -args = api.RenameCode_Args( +args = api.RenameCodeArgs( package_root="/mock/path", symbol_path="a", source_codes={"/mock/path/main.k": "a = 1\nb = a"}, @@ -518,7 +518,7 @@ Python Code ```python import kcl_lib.api as api -args = api.Test_Args( +args = api.TestArgs( pkg_list=["path/to/testing/pkg/..."], ) api_instance = api.API() @@ -550,7 +550,7 @@ Python Code ```python import kcl_lib.api as api -args = api.LoadSettingsFiles_Args( +args = api.LoadSettingsFilesArgs( work_dir=".", files=["kcl.yaml"] ) api_instance = api.API() @@ -590,7 +590,7 @@ Python Code ```python import kcl_lib.api as api -args = api.UpdateDependencies_Args( +args = api.UpdateDependenciesArgs( manifest_path="module" ) api_instance = api.API() @@ -636,12 +636,12 @@ Python Code ```python import kcl_lib.api as api -args = api.UpdateDependencies_Args( +args = api.UpdateDependenciesArgs( manifest_path="module" ) api_instance = api.API() result = api_instance.update_dependencies(args) -exec_args = api.ExecProgram_Args( +exec_args = api.ExecProgramArgs( k_filename_list=["module/main.k"], external_pkgs=result.external_pkgs, ) diff --git a/docs/reference/xlang-api/rest-api.md b/docs/reference/xlang-api/rest-api.md index b9a9ab738..21ab13e1d 100644 --- a/docs/reference/xlang-api/rest-api.md +++ b/docs/reference/xlang-api/rest-api.md @@ -32,30 +32,30 @@ The complete `BuiltinService` is defined by Protobuf: ```protobuf service BuiltinService { - rpc Ping(Ping_Args) returns(Ping_Result); - rpc ListMethod(ListMethod_Args) returns(ListMethod_Result); + rpc Ping(PingArgs) returns(PingResult); + rpc ListMethod(ListMethodArgs) returns(ListMethodResult); } -message Ping_Args { +message PingArgs { string value = 1; } -message Ping_Result { +message PingResult { string value = 1; } -message ListMethod_Args { +message ListMethodArgs { // empty } -message ListMethod_Result { +message ListMethodResult { repeated string method_name_list = 1; } ``` The `Ping` method can verify whether the service is normal, and the `ListMethod` method can query the list of all services and functions provided. -## 3. `KclvmService` +## 3. `KclService` -The `KclvmService` service is a service related to KCL functionality. The usage is the same as the `BuiltinService` service. +The `KclService` service is a service related to KCL functionality. The usage is the same as the `BuiltinService` service. For example, there is the following `Person` structure definition: @@ -73,10 +73,10 @@ Then we want to use `Person` to verify the following JSON data: { "key": "value" } ``` -This can be done through the `ValidateCode` method of the `KclvmService` service. Refer to the `ValidateCode_Args` structure of the `ValidateCode` method: +This can be done through the `ValidateCode` method of the `KclService` service. Refer to the `ValidateCodeArgs` structure of the `ValidateCode` method: ```protobuf -message ValidateCode_Args { +message ValidateCodeArgs { string data = 1; string code = 2; string schema = 3; @@ -85,7 +85,7 @@ message ValidateCode_Args { } ``` -Construct the JSON data required by the POST request according to the `ValidateCode_Args` structure, which contains the `Person` definition and the JSON data to be verified: +Construct the JSON data required by the POST request according to the `ValidateCodeArgs` structure, which contains the `Person` definition and the JSON data to be verified: ```json { @@ -98,7 +98,7 @@ Save this JSON data to the `vet-hello.json` file and verify it with the followin ```shell $ curl -X POST \ - http://127.0.0.1:2021/api:protorpc/KclvmService.ValidateCode \ + http://127.0.0.1:2021/api:protorpc/KclService.ValidateCode \ -H "accept: application/json" \ --data @./vet-hello.json { @@ -169,14 +169,14 @@ message Message { // Service for built-in functionality. service BuiltinService { // Sends a ping request. - rpc Ping(Ping_Args) returns (Ping_Result); + rpc Ping(PingArgs) returns (PingResult); // Lists available methods. - rpc ListMethod(ListMethod_Args) returns (ListMethod_Result); + rpc ListMethod(ListMethodArgs) returns (ListMethodResult); } // Service for KCL VM interactions. -service KclvmService { - /// Ping KclvmService, return the same value as the parameter +service KclService { + /// Ping KclService, return the same value as the parameter /// /// # Examples /// @@ -200,9 +200,9 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc Ping(Ping_Args) returns (Ping_Result); + rpc Ping(PingArgs) returns (PingResult); - /// GetVersion KclvmService, return the kclvm service version information + /// GetVersion KclService, return the kclvm service version information /// /// # Examples /// @@ -227,7 +227,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc GetVersion(GetVersion_Args) returns (GetVersion_Result); + rpc GetVersion(GetVersionArgs) returns (GetVersionResult); /// Parse KCL program with entry files. /// @@ -255,7 +255,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc ParseProgram(ParseProgram_Args) returns (ParseProgram_Result); + rpc ParseProgram(ParseProgramArgs) returns (ParseProgramResult); /// Parse KCL single file to Module AST JSON string with import dependencies /// and parse errors. @@ -284,7 +284,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc ParseFile(ParseFile_Args) returns (ParseFile_Result); + rpc ParseFile(ParseFileArgs) returns (ParseFileResult); /// load_package provides users with the ability to parse kcl program and semantic model /// information including symbols, types, definitions, etc. @@ -323,7 +323,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc LoadPackage(LoadPackage_Args) returns (LoadPackage_Result); + rpc LoadPackage(LoadPackageArgs) returns (LoadPackageResult); /// list_options provides users with the ability to parse kcl program and get all option information. /// @@ -353,7 +353,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc ListOptions(ParseProgram_Args) returns (ListOptions_Result); + rpc ListOptions(ParseProgramArgs) returns (ListOptionsResult); /// list_variables provides users with the ability to parse kcl program and get all variables by specs. /// @@ -388,7 +388,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc ListVariables(ListVariables_Args) returns (ListVariables_Result); + rpc ListVariables(ListVariablesArgs) returns (ListVariablesResult); /// Execute KCL file with args. **Note that it is not thread safe.** /// @@ -481,7 +481,7 @@ service KclvmService { /// "id": 4 /// } /// ``` - rpc ExecProgram(ExecProgram_Args) returns (ExecProgram_Result); + rpc ExecProgram(ExecProgramArgs) returns (ExecProgramResult); /// Build the KCL program to an artifact. /// @@ -511,7 +511,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc BuildProgram(BuildProgram_Args) returns (BuildProgram_Result); + rpc BuildProgram(BuildProgramArgs) returns (BuildProgramResult); /// Execute the KCL artifact with args. **Note that it is not thread safe.** /// @@ -544,7 +544,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc ExecArtifact(ExecArtifact_Args) returns (ExecProgram_Result); + rpc ExecArtifact(ExecArtifactArgs) returns (ExecProgramResult); /// Override KCL file with args. /// @@ -572,7 +572,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc OverrideFile(OverrideFile_Args) returns (OverrideFile_Result); + rpc OverrideFile(OverrideFileArgs) returns (OverrideFileResult); /// Get schema type mapping. /// @@ -619,7 +619,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc GetSchemaTypeMapping(GetSchemaTypeMapping_Args) returns (GetSchemaTypeMapping_Result); + rpc GetSchemaTypeMapping(GetSchemaTypeMappingArgs) returns (GetSchemaTypeMappingResult); /// Format code source. /// @@ -645,7 +645,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc FormatCode(FormatCode_Args) returns (FormatCode_Result); + rpc FormatCode(FormatCodeArgs) returns (FormatCodeResult); /// Format KCL file or directory path contains KCL files and returns the changed file paths. /// @@ -671,7 +671,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc FormatPath(FormatPath_Args) returns (FormatPath_Result); + rpc FormatPath(FormatPathArgs) returns (FormatPathResult); /// Lint files and return error messages including errors and warnings. /// @@ -697,7 +697,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc LintPath(LintPath_Args) returns (LintPath_Result); + rpc LintPath(LintPathArgs) returns (LintPathResult); /// Validate code using schema and data strings. /// @@ -727,9 +727,9 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc ValidateCode(ValidateCode_Args) returns (ValidateCode_Result); + rpc ValidateCode(ValidateCodeArgs) returns (ValidateCodeResult); - rpc ListDepFiles(ListDepFiles_Args) returns (ListDepFiles_Result); + rpc ListDepFiles(ListDepFilesArgs) returns (ListDepFilesResult); /// Build setting file config from args. /// /// # Examples @@ -769,7 +769,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc LoadSettingsFiles(LoadSettingsFiles_Args) returns (LoadSettingsFiles_Result); + rpc LoadSettingsFiles(LoadSettingsFilesArgs) returns (LoadSettingsFilesResult); /// Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. /// Return the file paths that got changed. @@ -799,7 +799,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc Rename(Rename_Args) returns (Rename_Result); + rpc Rename(RenameArgs) returns (RenameResult); /// Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. /// @@ -832,7 +832,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc RenameCode(RenameCode_Args) returns (RenameCode_Result); + rpc RenameCode(RenameCodeArgs) returns (RenameCodeResult); /// Test KCL packages with test arguments. /// @@ -861,7 +861,7 @@ service KclvmService { /// "id": 1 /// } /// ``` - rpc Test(Test_Args) returns (Test_Result); + rpc Test(TestArgs) returns (TestResult); /// Download and update dependencies defined in the kcl.mod file. /// @@ -911,28 +911,28 @@ service KclvmService { /// "id": 2 /// } /// ``` - rpc UpdateDependencies(UpdateDependencies_Args) returns (UpdateDependencies_Result); + rpc UpdateDependencies(UpdateDependenciesArgs) returns (UpdateDependenciesResult); } // Message for ping request arguments. -message Ping_Args { +message PingArgs { // Value to be sent in the ping request. string value = 1; } // Message for ping response. -message Ping_Result { +message PingResult { // Value received in the ping response. string value = 1; } // Message for version request arguments. Empty message. -message GetVersion_Args { +message GetVersionArgs { // empty } // Message for version response. -message GetVersion_Result { +message GetVersionResult { // KCL version. string version = 1; // Checksum of the KCL version. @@ -944,18 +944,18 @@ message GetVersion_Result { } // Message for list method request arguments. Empty message. -message ListMethod_Args { +message ListMethodArgs { // empty } // Message for list method response. -message ListMethod_Result { +message ListMethodResult { // List of available method names. repeated string method_name_list = 1; } // Message for parse file request arguments. -message ParseFile_Args { +message ParseFileArgs { // Path of the file to be parsed. string path = 1; // Source code to be parsed. @@ -965,7 +965,7 @@ message ParseFile_Args { } // Message for parse file response. -message ParseFile_Result { +message ParseFileResult { // Abstract Syntax Tree (AST) in JSON format. string ast_json = 1; // File dependency paths. @@ -975,7 +975,7 @@ message ParseFile_Result { } // Message for parse program request arguments. -message ParseProgram_Args { +message ParseProgramArgs { // Paths of the program files to be parsed. repeated string paths = 1; // Source codes to be parsed. @@ -985,7 +985,7 @@ message ParseProgram_Args { } // Message for parse program response. -message ParseProgram_Result { +message ParseProgramResult { // Abstract Syntax Tree (AST) in JSON format. string ast_json = 1; // Returns the files in the order they should be compiled. @@ -995,9 +995,9 @@ message ParseProgram_Result { } // Message for load package request arguments. -message LoadPackage_Args { +message LoadPackageArgs { // Arguments for parsing the program. - ParseProgram_Args parse_args = 1; + ParseProgramArgs parse_args = 1; // Flag indicating whether to resolve AST. bool resolve_ast = 2; // Flag indicating whether to load built-in modules. @@ -1007,7 +1007,7 @@ message LoadPackage_Args { } // Message for load package response. -message LoadPackage_Result { +message LoadPackageResult { // Program Abstract Syntax Tree (AST) in JSON format. string program = 1; // Returns the files in the order they should be compiled. @@ -1031,7 +1031,7 @@ message LoadPackage_Result { } // Message for list options response. -message ListOptions_Result { +message ListOptionsResult { // List of available options. repeated OptionHelp options = 2; } @@ -1101,7 +1101,7 @@ message ScopeIndex { } // Message for execute program request arguments. -message ExecProgram_Args { +message ExecProgramArgs { // Working directory. string work_dir = 1; // List of KCL filenames. @@ -1141,7 +1141,7 @@ message ExecProgram_Args { } // Message for execute program response. -message ExecProgram_Result { +message ExecProgramResult { // Result in JSON format. string json_result = 1; // Result in YAML format. @@ -1153,76 +1153,76 @@ message ExecProgram_Result { } // Message for build program request arguments. -message BuildProgram_Args { +message BuildProgramArgs { // Arguments for executing the program. - ExecProgram_Args exec_args = 1; + ExecProgramArgs exec_args = 1; // Output path. string output = 2; } // Message for build program response. -message BuildProgram_Result { +message BuildProgramResult { // Path of the built program. string path = 1; } // Message for execute artifact request arguments. -message ExecArtifact_Args { +message ExecArtifactArgs { // Path of the artifact. string path = 1; // Arguments for executing the program. - ExecProgram_Args exec_args = 2; + ExecProgramArgs exec_args = 2; } // Message for reset plugin request arguments. -message ResetPlugin_Args { +message ResetPluginArgs { // Root path for the plugin. string plugin_root = 1; } // Message for reset plugin response. Empty message. -message ResetPlugin_Result { +message ResetPluginResult { // empty } // Message for format code request arguments. -message FormatCode_Args { +message FormatCodeArgs { // Source code to be formatted. string source = 1; } // Message for format code response. -message FormatCode_Result { +message FormatCodeResult { // Formatted code as bytes. bytes formatted = 1; } // Message for format file path request arguments. -message FormatPath_Args { +message FormatPathArgs { // Path of the file to format. string path = 1; } // Message for format file path response. -message FormatPath_Result { +message FormatPathResult { // List of changed file paths. repeated string changed_paths = 1; } // Message for lint file path request arguments. -message LintPath_Args { +message LintPathArgs { // Paths of the files to lint. repeated string paths = 1; } // Message for lint file path response. -message LintPath_Result { +message LintPathResult { // List of lint results. repeated string results = 1; } // Message for override file request arguments. -message OverrideFile_Args { +message OverrideFileArgs { // Path of the file to override. string file = 1; // List of override specifications. @@ -1232,7 +1232,7 @@ message OverrideFile_Args { } // Message for override file response. -message OverrideFile_Result { +message OverrideFileResult { // Result of the override operation. bool result = 1; // List of parse errors encountered. @@ -1252,7 +1252,7 @@ message VariableList { } // Message for list variables request arguments. -message ListVariables_Args { +message ListVariablesArgs { // Files to be processed. repeated string files = 1; // Specifications for variables. @@ -1262,7 +1262,7 @@ message ListVariables_Args { } // Message for list variables response. -message ListVariables_Result { +message ListVariablesResult { // Map of variable lists by file. map variables = 1; // List of unsupported codes. @@ -1294,21 +1294,21 @@ message MapEntry { } // Message for get schema type mapping request arguments. -message GetSchemaTypeMapping_Args { +message GetSchemaTypeMappingArgs { // Arguments for executing the program. - ExecProgram_Args exec_args = 1; + ExecProgramArgs exec_args = 1; // Name of the schema. string schema_name = 2; } // Message for get schema type mapping response. -message GetSchemaTypeMapping_Result { +message GetSchemaTypeMappingResult { // Map of schema type mappings. map schema_type_mapping = 1; } // Message for validate code request arguments. -message ValidateCode_Args { +message ValidateCodeArgs { // Path to the data file. string datafile = 1; // Data content. @@ -1326,7 +1326,7 @@ message ValidateCode_Args { } // Message for validate code response. -message ValidateCode_Result { +message ValidateCodeResult { // Flag indicating if validation was successful. bool success = 1; // Error message from validation. @@ -1344,7 +1344,7 @@ message Position { } // Message for list dependency files request arguments. -message ListDepFiles_Args { +message ListDepFilesArgs { // Working directory. string work_dir = 1; // Flag to use absolute paths. @@ -1356,7 +1356,7 @@ message ListDepFiles_Args { } // Message for list dependency files response. -message ListDepFiles_Result { +message ListDepFilesResult { // Root package path. string pkgroot = 1; // Package path. @@ -1371,7 +1371,7 @@ message ListDepFiles_Result { // --------------------------------------------------------------------------------- // Message for load settings files request arguments. -message LoadSettingsFiles_Args { +message LoadSettingsFilesArgs { // Working directory. string work_dir = 1; // Setting files to load. @@ -1379,7 +1379,7 @@ message LoadSettingsFiles_Args { } // Message for load settings files response. -message LoadSettingsFiles_Result { +message LoadSettingsFilesResult { // KCL CLI configuration. CliConfig kcl_cli_configs = 1; // List of KCL options as key-value pairs. @@ -1429,7 +1429,7 @@ message KeyValuePair { // --------------------------------------------------------------------------------- // Message for rename request arguments. -message Rename_Args { +message RenameArgs { // File path to the package root. string package_root = 1; // Path to the target symbol to be renamed. @@ -1441,7 +1441,7 @@ message Rename_Args { } // Message for rename response. -message Rename_Result { +message RenameResult { // List of file paths that got changed. repeated string changed_files = 1; } @@ -1453,7 +1453,7 @@ message Rename_Result { // --------------------------------------------------------------------------------- // Message for rename code request arguments. -message RenameCode_Args { +message RenameCodeArgs { // File path to the package root. string package_root = 1; // Path to the target symbol to be renamed. @@ -1465,7 +1465,7 @@ message RenameCode_Args { } // Message for rename code response. -message RenameCode_Result { +message RenameCodeResult { // Map of changed code with filename as key and modified code as value. map changed_codes = 1; } @@ -1476,9 +1476,9 @@ message RenameCode_Result { // --------------------------------------------------------------------------------- // Message for test request arguments. -message Test_Args { +message TestArgs { // Execution program arguments. - ExecProgram_Args exec_args = 1; + ExecProgramArgs exec_args = 1; // List of KCL package paths to be tested. repeated string pkg_list = 2; // Regular expression for filtering tests to run. @@ -1488,7 +1488,7 @@ message Test_Args { } // Message for test response. -message Test_Result { +message TestResult { // List of test case information. repeated TestCaseInfo info = 2; } @@ -1511,7 +1511,7 @@ message TestCaseInfo { // --------------------------------------------------------------------------------- // Message for update dependencies request arguments. -message UpdateDependencies_Args { +message UpdateDependenciesArgs { // Path to the manifest file. string manifest_path = 1; // Flag to vendor dependencies locally. @@ -1519,7 +1519,7 @@ message UpdateDependencies_Args { } // Message for update dependencies response. -message UpdateDependencies_Result { +message UpdateDependenciesResult { // List of external packages updated. repeated ExternalPkg external_pkgs = 3; } diff --git a/docs/reference/xlang-api/swift-api.md b/docs/reference/xlang-api/swift-api.md index 71f017662..3720809e3 100644 --- a/docs/reference/xlang-api/swift-api.md +++ b/docs/reference/xlang-api/swift-api.md @@ -12,7 +12,7 @@ The official [Swift KCL package](https://github.com/kcl-lang/lib/tree/main/swift import KclLib let api = API() -var execArgs = ExecProgram_Args() +var execArgs = ExecProgramArgs() execArgs.kFilenameList.append("schema.k") let result = try api.execProgram(execArgs) ``` diff --git a/docs/tools/Ide/helix.md b/docs/tools/Ide/helix.md index 29ccae273..bcffea284 100644 --- a/docs/tools/Ide/helix.md +++ b/docs/tools/Ide/helix.md @@ -22,6 +22,7 @@ sidebar_position: 4 ``` - **Step 2.** Amend your Helix `languages.toml` file: + ```toml [[language]] name = "kcl" @@ -33,6 +34,7 @@ sidebar_position: 4 [language-server.kcl-lsp] command = "kcl-language-server" ``` + - **Step 3.** Reopen Helix, create a KCL file, and begin your KCL journey! ## Features @@ -40,6 +42,7 @@ sidebar_position: 4 This extension provides comprehensive coding assistance based on the Language Server Protocol. + - **Code Completion:** Completion for keywords, variable names, attributes, and more - **Structure:** View the main definition (schema definition) and variables in KCL files diff --git a/docs/user_docs/guides/working-with-konfig/3-quick-start.md b/docs/user_docs/guides/working-with-konfig/3-quick-start.md index d21bee923..e3093ebdc 100644 --- a/docs/user_docs/guides/working-with-konfig/3-quick-start.md +++ b/docs/user_docs/guides/working-with-konfig/3-quick-start.md @@ -69,24 +69,24 @@ spec: app.k8s.io/component: sampleapp-dev spec: containers: - - env: - - name: MY_ENV - value: MY_VALUE - image: nginx:1.7.8 - name: main - ports: - - containerPort: 80 - protocol: TCP - resources: - limits: - cpu: '100m' - memory: '100Mi' - ephemeral-storage: '1Gi' - requests: - cpu: '100m' - memory: '100Mi' - ephemeral-storage: '1Gi' - volumeMounts: [] + - env: + - name: MY_ENV + value: MY_VALUE + image: nginx:1.7.8 + name: main + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + requests: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + volumeMounts: [] --- apiVersion: v1 kind: Namespace @@ -100,9 +100,9 @@ metadata: namespace: sampleappns-dev spec: ports: - - nodePort: 30201 - port: 80 - targetPort: 80 + - nodePort: 30201 + port: 80 + targetPort: 80 selector: app.kubernetes.io/name: sampleapp app.kubernetes.io/env: dev @@ -157,24 +157,24 @@ spec: app.k8s.io/component: sampleapp-dev spec: containers: - - env: - - name: MY_ENV - value: MY_VALUE - image: nginx:1.7.8 - name: main - ports: - - containerPort: 80 - protocol: TCP - resources: - limits: - cpu: '100m' - memory: '100Mi' - ephemeral-storage: '1Gi' - requests: - cpu: '100m' - memory: '100Mi' - ephemeral-storage: '1Gi' - volumeMounts: [] + - env: + - name: MY_ENV + value: MY_VALUE + image: nginx:1.7.8 + name: main + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + requests: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + volumeMounts: [] --- apiVersion: v1 kind: Namespace @@ -188,9 +188,9 @@ metadata: namespace: sampleappns-dev spec: ports: - - nodePort: 30201 - port: 80 - targetPort: 80 + - nodePort: 30201 + port: 80 + targetPort: 80 selector: app.kubernetes.io/name: sampleapp app.kubernetes.io/env: dev diff --git a/docs/user_docs/guides/working-with-konfig/4-best-practice.md b/docs/user_docs/guides/working-with-konfig/4-best-practice.md index 92a0e77e5..6e6a82829 100644 --- a/docs/user_docs/guides/working-with-konfig/4-best-practice.md +++ b/docs/user_docs/guides/working-with-konfig/4-best-practice.md @@ -346,9 +346,9 @@ The output is ```yaml cpuMap: - '1': 256 - '2': 512 - '3': 1024 + "1": 256 + "2": 512 + "3": 1024 cpu: 256 ``` diff --git a/docs/user_docs/support/faq-kcl.md b/docs/user_docs/support/faq-kcl.md index 8d953a419..6095390ea 100644 --- a/docs/user_docs/support/faq-kcl.md +++ b/docs/user_docs/support/faq-kcl.md @@ -1051,6 +1051,7 @@ import model # Error: recursively loading ## 26. When can import be omitted? KCL files in the same folder, but not in the main package, can refer to each other without importing. For example, for the following directory structure: + ``` . └── root @@ -1740,8 +1741,6 @@ configNew: key2: value2 ``` - - ### The solution to the conflicting values on the attribute 'attr' between {value1} and {value2} error in KCL When an error like conflicting values on the attribute 'attr' between {value1} and {value2} occurs in KCL, it is usually a problem with the use of the merge attribute operator `:`, indicating that when the `value1` and `value2` configurations are merged, the attribute A conflict error occurred at `attr`. In general, modify the attr attribute of value2 to other attribute operators, use `=` to indicate overwrite, and use `+=` to indicate addition @@ -2720,12 +2719,14 @@ In summary, KCL's mixins and protocols combine concepts from various programming We can use the `--show-hidden` or `-H` flag when use the KCL CLI to run KCL files. e.g.: main.k + ```python a = 1 _b = 2 ``` The output maybe as follows with the command `kcl run main.k -H` + ```yaml a: 1 _b: 2 diff --git a/i18n/zh-CN/docusaurus-plugin-content-blog/2024-12-24-kcl-0.11.0-release/index.md b/i18n/zh-CN/docusaurus-plugin-content-blog/2024-12-24-kcl-0.11.0-release/index.md index 74c019e9d..31c86796f 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-blog/2024-12-24-kcl-0.11.0-release/index.md +++ b/i18n/zh-CN/docusaurus-plugin-content-blog/2024-12-24-kcl-0.11.0-release/index.md @@ -20,7 +20,7 @@ KCL 团队很高兴地宣布 **KCL v0.11.0 新版本现在已经可用**!本 **感谢 KCL 在 v0.10 - v0.11 版本迭代所有社区参与者,以下排名不分先后** -_@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @eminaktas, @Gmin2, @tvandinther, @diefans, @nkabir, @suin, @Chewie, @lwz23, @eminaktas,@steeling, @bozaro, @cakemanny, @Yufeireal, @andrzejgorski, @yonas, @dansrogers, @SkySingh04, @jellllly420, @slashexx, @xnull, @diefans, @zflat, @vfarcic, @spastorclovr, @patpicos, @mproffitt, @fraenkel, @irizzant, @vfarcic, @patpicos, @mproffitt, @fraenkel, @Clint, @Christopher Haar, @ron18219, @Zack Zhang, @Alexander Fuchs, @Smaine Kahlouch, @Yvan da Silva, @Jakob Maležič, @Ryan Rueth, @Christopher Haar, @kesser, @Justin B, @Evgeny Shepelyuk, @Smaine Kahlouch, @KennyZ, @Mark Altmann (Wompi), @Peter Boat, @Hai Wu, @Evgeny Shepelyuk, @anshuman singh, @Carl-Fredrik, @Larry Gadallah, @Kevin Sztern, @Nick Atzert, @Tobias Kässer, @Mike, @john thompson, @Sky Singh, @suin, @Tom van Dinther, @Stefano Borrelli, @Valer Orlovsky, @Jacob Colvin, @Sjuul Janssen, @Vyacheslav Terdunov, @Yury Tsarev_ +_@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @eminaktas, @Gmin2, @tvandinther, @diefans, @nkabir, @suin, @Chewie, @lwz23, @eminaktas,@steeling, @bozaro, @cakemanny, @Yufeireal, @andrzejgorski, @yonas, @dansrogers, @SkySingh04, @jellllly420, @slashexx, @xnull, @diefans, @zflat, @vfarcic, @spastorclovr, @patpicos, @mproffitt, @fraenkel, @irizzant, @vfarcic, @patpicos, @mproffitt, @fraenkel, @Clint, @Christopher Haar, @ron18219, @Zack Zhang, @Alexander Fuchs, @Smaine Kahlouch, @Yvan da Silva, @Jakob Maležič, @Ryan Rueth, @Christopher Haar, @kesser, @Justin B, @Evgeny Shepelyuk, @Smaine Kahlouch, @KennyZ, @Mark Altmann (Wompi), @Peter Boat, @Hai Wu, @Evgeny Shepelyuk, @anshuman singh, @Carl-Fredrik, @Larry Gadallah, @Kevin Sztern, @Nick Atzert, @Tobias Kässer, @Mike, @john thompson, @Sky Singh, @suin, @Tom van Dinther, @Stefano Borrelli, @Valer Orlovsky, @Jacob Colvin, @Sjuul Janssen, @Vyacheslav Terdunov, @Yury Tsarev_ ## 📚 重点更新内容 @@ -30,7 +30,7 @@ _@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @emi - KCL 新增对 Alpine Linux(musl) 平台的支持。 - KCL 重构了 Parser 部分的实现,重新组织了 import 依赖的 parse 流程。 -- KCL 优化了 schema attribute 中对 ** 表达式的类型解析。 +- KCL 优化了 schema attribute 中对 \*\* 表达式的类型解析。 - KCL 修复了 lambda 表达式嵌套调用时不生效的问题。 - KCL 修复了 schema mixin parse 内存泄露的问题。 - KCL 修复了在有类型声明的赋值语句中函数调用表达式中的类型提升。 @@ -39,11 +39,11 @@ _@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @emi #### 工具链 - 包管理工具版本选择算法上线。在 v0.11.0 版本中, KCL 包管理工具支持对依赖图中出现的同一个三方库的不同版本号进行选择,KCL 包管理工具参考了 go mod 的 mvs 算法, -为了尽可能保证兼容性,包管理工具目前倾向于选择依赖图中出现的最新的版本而不是已经 release 的最新版本。 -在 v0.11.0 版本中,版本选择默认关闭,通过设置环境变量 `export KPM_FEATURE_GATES="SupportMVS=true"` 控制是否开启版本选择。 + 为了尽可能保证兼容性,包管理工具目前倾向于选择依赖图中出现的最新的版本而不是已经 release 的最新版本。 + 在 v0.11.0 版本中,版本选择默认关闭,通过设置环境变量 `export KPM_FEATURE_GATES="SupportMVS=true"` 控制是否开启版本选择。 - 包管理工具新增了新的本地三方库缓存结构,在 v0.11.0 版本中,KCL 包管理工具实现了新的本地三方库缓存结构,新的存储缓存结构对下载 git 仓库性能平均提升 88%。 -在 v0.11.0 版本中,新的缓存结构默认关闭,通过设置环境变量 `export KPM_FEATURE_GATES="SupportNewStorage=true"` 控制是否启用新的本地三方库缓存。 + 在 v0.11.0 版本中,新的缓存结构默认关闭,通过设置环境变量 `export KPM_FEATURE_GATES="SupportNewStorage=true"` 控制是否启用新的本地三方库缓存。 - 修复 `kcl fmt` 代码注释的格式化错误。 - 修复 `kcl fmt` 在处理行连接符和注释组合时的错误。 @@ -52,11 +52,11 @@ _@adamwg, @steeling, @dennybaa, @liangyuanpeng, @NishantBansal2003, @mayrf, @emi - KCL IntelliJ 插件发布 0.4.0 版本,支持 LSP4IJ - IDE 可以补全目录中未 import 的 schema,并且自动补充包的 import 语句 -![complete](/img/blog/2024-12-06-kcl-0.11.0-release/complete.gif) + ![complete](/img/blog/2024-12-06-kcl-0.11.0-release/complete.gif) - IDE 新增了 Config 块中 key 的类型 hint。 -![hint](/img/blog/2024-12-06-kcl-0.11.0-release/hint.png) + ![hint](/img/blog/2024-12-06-kcl-0.11.0-release/hint.png) - IDE schema hover 中提供了 attr 默认值信息。 -![hover](/img/blog/2024-12-06-kcl-0.11.0-release/hover.png) + ![hover](/img/blog/2024-12-06-kcl-0.11.0-release/hover.png) - 修复了 IDE 在 Windows 系统中的异常。 - 修复了 IDE 在复合赋值运算语句中异常的问题。 - 区分了 `any` 关键字和类型的高亮 @@ -83,6 +83,7 @@ import crypto sha_filesha512 = crypto.filesha512("test.txt") sha_fileblake3 = crypto.fileblake3("test.txt") ``` + - 修复 `manifests.yaml_stream` 中 `ignore_private=False` 参数 不生效的问题。 #### 三方库 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/reference/model/regex.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/reference/model/regex.md index 380df50b9..5470831ef 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-docs/current/reference/model/regex.md +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/reference/model/regex.md @@ -23,6 +23,7 @@ regex_replace = regex.replace(regex_source, ",", "|") `match(string: str, pattern: str) -> bool` 尝试在字符串开头应用模式 `pattern`,找到了任何匹配项则返回 `True`,返回 `False` 表示没有找到匹配项 + ```python import regex diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.10/reference/model/regex.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.10/reference/model/regex.md index 380df50b9..5470831ef 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.10/reference/model/regex.md +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.10/reference/model/regex.md @@ -23,6 +23,7 @@ regex_replace = regex.replace(regex_source, ",", "|") `match(string: str, pattern: str) -> bool` 尝试在字符串开头应用模式 `pattern`,找到了任何匹配项则返回 `True`,返回 `False` 表示没有找到匹配项 + ```python import regex diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11.json new file mode 100644 index 000000000..f27afbace --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11.json @@ -0,0 +1,136 @@ +{ + "sidebar.user_docs.category.Getting Started": { + "message": "快速开始" + }, + "sidebar.user_docs.category.Introduction": { + "message": "简介" + }, + "sidebar.user_docs.category.Guides": { + "message": "用户手册" + }, + "sidebar.user_docs.guides.category.Automation": { + "message": "自动化" + }, + "sidebar.user_docs.category.Configuration": { + "message": "配置" + }, + "sidebar.user_docs.category.Data Integration": { + "message": "数据集成" + }, + "sidebar.user_docs.category.Package Management": { + "message": "包管理工具" + }, + "sidebar.user_docs.category.Package Management Tools": { + "message": "包管理工具" + }, + "sidebar.user_docs.category.How to": { + "message": "如何使用" + }, + "sidebar.user_docs.category.Schema Definition": { + "message": "模型定义" + }, + "sidebar.user_docs.category.Validation": { + "message": "验证" + }, + "sidebar.user_docs.category.Concepts": { + "message": "核心概念" + }, + "sidebar.user_docs.category.FAQ": { + "message": "常见问答" + }, + "sidebar.reference.category.Tutorial": { + "message": "教程" + }, + "sidebar.reference.category.Code Lab": { + "message": "代码实验室" + }, + "sidebar.reference.category.Spec": { + "message": "语言规范" + }, + "sidebar.reference.category.Errors and Warnings": { + "message": "错误与警告" + }, + "sidebar.reference.category.Types": { + "message": "类型系统" + }, + "sidebar.reference.category.System Package": { + "message": "系统模块" + }, + "sidebar.reference.category.Plugin System": { + "message": "插件系统" + }, + "sidebar.reference.category.Multi-Language": { + "message": "多语言集成" + }, + "sidebar.reference.category.Cheat Sheet": { + "message": "备忘表" + }, + "sidebar.reference.category.Package Management": { + "message": "包管理工具" + }, + "sidebar.reference.category.Command Reference": { + "message": "命令参考" + }, + "sidebar.reference.category.Advanced-Concepts": { + "message": "进阶概念" + }, + "sidebar.reference.category.Best-Practices": { + "message": "最佳实践" + }, + "sidebar.tools.category.Command Line Tools": { + "message": "命令行工具" + }, + "sidebar.tools.category.KCL Tools": { + "message": "语言工具" + }, + "sidebar.tools.category.Package Management Tools": { + "message": "包管理工具" + }, + "sidebar.tools.category.OpenAPI Tools": { + "message": "OpenAPI 工具" + }, + "sidebar.community.category.Community": { + "message": "简介" + }, + "sidebar.community.category.Types": { + "message": "类型系统" + }, + "sidebar.community.category.Contribution Guide": { + "message": "贡献指南" + }, + "sidebar.community.category.Release Policy": { + "message": "发布策略" + }, + "sidebar.docs.category.GitOps": { + "message": "GitOps", + "description": "The label for category GitOps in sidebar docs" + }, + "sidebar.docs.category.CI Integration": { + "message": "CI 集成", + "description": "The label for category CI Integration in sidebar docs" + }, + "sidebar.user_docs.category.GitOps": { + "message": "GitOps", + "description": "The label for category GitOps in sidebar user_docs" + }, + "sidebar.user_docs.category.CI Integration": { + "message": "CI 集成", + "description": "The label for category CI Integration in sidebar user_docs" + }, + "sidebar.docs.category.Mutate or Validate Kubernetes Manifests": { + "message": "编辑或验证 Kubernetes 资源", + "description": "The label for category Mutate or Validate Kubernetes Manifests in sidebar docs" + }, + "sidebar.user_docs.category.Mutate or Validate Kubernetes Manifests": { + "message": "编辑或验证 Kubernetes 资源", + "description": "The label for category Mutate or Validate Kubernetes Manifests in sidebar user_docs" + }, + "sidebar.docs.category.Secret Management": { + "message": "敏感信息管理", + "description": "The label for category Secret Management in sidebar docs" + }, + "sidebar.user_docs.category.Secret Management": { + "message": "敏感信息管理", + "description": "The label for category Secret Management in sidebar user_docs" + } +} \ No newline at end of file diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11/reference/model/regex.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11/reference/model/regex.md index 380df50b9..5470831ef 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11/reference/model/regex.md +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.11/reference/model/regex.md @@ -23,6 +23,7 @@ regex_replace = regex.replace(regex_source, ",", "|") `match(string: str, pattern: str) -> bool` 尝试在字符串开头应用模式 `pattern`,找到了任何匹配项则返回 `True`,返回 `False` 表示没有找到匹配项 + ```python import regex diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12.json new file mode 100644 index 000000000..f27afbace --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12.json @@ -0,0 +1,136 @@ +{ + "sidebar.user_docs.category.Getting Started": { + "message": "快速开始" + }, + "sidebar.user_docs.category.Introduction": { + "message": "简介" + }, + "sidebar.user_docs.category.Guides": { + "message": "用户手册" + }, + "sidebar.user_docs.guides.category.Automation": { + "message": "自动化" + }, + "sidebar.user_docs.category.Configuration": { + "message": "配置" + }, + "sidebar.user_docs.category.Data Integration": { + "message": "数据集成" + }, + "sidebar.user_docs.category.Package Management": { + "message": "包管理工具" + }, + "sidebar.user_docs.category.Package Management Tools": { + "message": "包管理工具" + }, + "sidebar.user_docs.category.How to": { + "message": "如何使用" + }, + "sidebar.user_docs.category.Schema Definition": { + "message": "模型定义" + }, + "sidebar.user_docs.category.Validation": { + "message": "验证" + }, + "sidebar.user_docs.category.Concepts": { + "message": "核心概念" + }, + "sidebar.user_docs.category.FAQ": { + "message": "常见问答" + }, + "sidebar.reference.category.Tutorial": { + "message": "教程" + }, + "sidebar.reference.category.Code Lab": { + "message": "代码实验室" + }, + "sidebar.reference.category.Spec": { + "message": "语言规范" + }, + "sidebar.reference.category.Errors and Warnings": { + "message": "错误与警告" + }, + "sidebar.reference.category.Types": { + "message": "类型系统" + }, + "sidebar.reference.category.System Package": { + "message": "系统模块" + }, + "sidebar.reference.category.Plugin System": { + "message": "插件系统" + }, + "sidebar.reference.category.Multi-Language": { + "message": "多语言集成" + }, + "sidebar.reference.category.Cheat Sheet": { + "message": "备忘表" + }, + "sidebar.reference.category.Package Management": { + "message": "包管理工具" + }, + "sidebar.reference.category.Command Reference": { + "message": "命令参考" + }, + "sidebar.reference.category.Advanced-Concepts": { + "message": "进阶概念" + }, + "sidebar.reference.category.Best-Practices": { + "message": "最佳实践" + }, + "sidebar.tools.category.Command Line Tools": { + "message": "命令行工具" + }, + "sidebar.tools.category.KCL Tools": { + "message": "语言工具" + }, + "sidebar.tools.category.Package Management Tools": { + "message": "包管理工具" + }, + "sidebar.tools.category.OpenAPI Tools": { + "message": "OpenAPI 工具" + }, + "sidebar.community.category.Community": { + "message": "简介" + }, + "sidebar.community.category.Types": { + "message": "类型系统" + }, + "sidebar.community.category.Contribution Guide": { + "message": "贡献指南" + }, + "sidebar.community.category.Release Policy": { + "message": "发布策略" + }, + "sidebar.docs.category.GitOps": { + "message": "GitOps", + "description": "The label for category GitOps in sidebar docs" + }, + "sidebar.docs.category.CI Integration": { + "message": "CI 集成", + "description": "The label for category CI Integration in sidebar docs" + }, + "sidebar.user_docs.category.GitOps": { + "message": "GitOps", + "description": "The label for category GitOps in sidebar user_docs" + }, + "sidebar.user_docs.category.CI Integration": { + "message": "CI 集成", + "description": "The label for category CI Integration in sidebar user_docs" + }, + "sidebar.docs.category.Mutate or Validate Kubernetes Manifests": { + "message": "编辑或验证 Kubernetes 资源", + "description": "The label for category Mutate or Validate Kubernetes Manifests in sidebar docs" + }, + "sidebar.user_docs.category.Mutate or Validate Kubernetes Manifests": { + "message": "编辑或验证 Kubernetes 资源", + "description": "The label for category Mutate or Validate Kubernetes Manifests in sidebar user_docs" + }, + "sidebar.docs.category.Secret Management": { + "message": "敏感信息管理", + "description": "The label for category Secret Management in sidebar docs" + }, + "sidebar.user_docs.category.Secret Management": { + "message": "敏感信息管理", + "description": "The label for category Secret Management in sidebar user_docs" + } +} \ No newline at end of file diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/_category_.json new file mode 100644 index 000000000..f763b5c8d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "社区", + "position": 5 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/_category_.json new file mode 100644 index 000000000..131bb8e32 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "贡献指南", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-code.md new file mode 100644 index 000000000..8e8392fea --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-code.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 2 +--- + +# 如何贡献代码? + +欢迎参与 KCL 共建贡献完善代码、完善代码文档和测试,同时也欢迎通过 Issue 提供反馈。本文主要针对修改和完善已有的代码,如果是希望增加 KCL 语言特性请通过 KEP 流程提交。 + +## 1. 代码和注释中的错别字 + +如果只是修改代码和注释中的错别字,不涉及代码逻辑的调整,那么可以直接在 Github 克隆仓库后直接修改并提交 PR。需要注意的是尽量保持代码风格一致。 + +## 2. 如何贡献 KCL 代码 + +- 先确保本地测试环境正常 +- 修改代码并补充测试 +- 本地测试通过后提交 PR + +## 3. 如何贡献 VS Code 插件代码 + +请参考 VS Code 插件仓库的相关文档 + +## 4. 开发流程相关代码 + +欢迎通过 Issue 和讨论组讨论。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-docs.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-docs.md new file mode 100644 index 000000000..7b846680d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute-docs.md @@ -0,0 +1,61 @@ +--- +sidebar_position: 1 +--- + +# 如何贡献文档? + +本文主要针对已有的文档做局部修改。如果是投稿博客文章、添加新的文档或者调整文档目录结构请先联系团队成员。 + +KCL 文档分为用户指南、开发文档、内部文档、参考手册和博客文章等,他们的区别如下: + +- 用户指南:对应使用文档,是让用户以最小的代价快速使用 KCL 工具完整工作,不要涉及太多的内部原理和实现 +- 开发文档:内部是怎么实现的,主要针对希望了解 KCL 原理和参与贡献和开发的同学 +- 内部文档:针对企业用户的一些内部场景定制的文档 +- 参考手册:KCL 语言、工具和 IDE 等全部特性的文档,内容覆盖最广但比较琐碎 +- 博客文章:没有特别的限制,可以是针对某些具体的场景、某些技术点或者是整体发展展望等分享文章 + +在贡献不同类型的文档时,最好能够结合上面的定位对不同的内容做一些适当的裁剪,给读者最佳体验。 + +## 1. 基本规范 + +- 除标题外,内部小标题尽量带编号,便于阅读 +- 工具自动输出的文档需要由到源代码的链接,小标题可以不带编号 +- 尽量不要贴大段的代码(30行以内),代码最好给出文字解释和对应的参考链接 +- 有图有真相,但是不推荐过度复杂的架构图 +- 内部链接:采用 `/docs/user_docs/getting-started/intro` 绝对路径形式 + +**标点和空格** + +- 在中文的文档中优先使用中文的标点 +- 中文和英文之间需要增加 1 个空格 +- 中文和数字之间需要增加 1 个空格 +- 中文使用全角标点,标点前后均不添加空格 +- 英文内容使用半角标点,标点后面加 1 个空格 +- 链接前后需要保留一个空格,但是段落开头和中文全角标点附近不用添加空格。 + +**图片和资源文件名** + +- 文件名和目录名只能用数字、英文字母、下划线 `_` 和减号 `-` 组成 +- 当前文档的图片放在当前目录的 images 目录下 +- 矢量图片可以通过 [drawio 离线版](https://github.com/jgraph/drawio-desktop/releases) 绘制(并同时提交源文件),以 200% 分辨率导出 png 格式图片 + +## 2. 使用文档内容的基本模式 + +每个使用文档可以看作是一个相对完整的分享或博客文章(参考手册不再此类)。使用文档遵循以下模式组织内容: + +1. 概览:本文希望解决什么问题,达到什么效果,可以先放最终效果截图 +1. 依赖的环境:需要安装什么工具,并给出相关链接 +1. 引入本文构建资源的关系图或架构图 + - 需要用到的 Konfig 模型,给出模型参考页面链接,以及对应的上游原始模型的文档链接 +1. 具体的操作步骤 + - 尽量确保最小化代码,甚至可以刻意隐藏一些干扰代码,同时给出完整代码对应的链接 + - 列出每个步骤命令的概要输出信息,并配以文字描述 +1. 给出测试方式 + - 尽量采用社区通用的方式(比如kube、curl命令、或浏览器)测试 + - 给出测试结果的截图(和开头呼应) +1. 总结和展望 + - 简单回顾当前操作的流程,以及一些可以展开的地方(可以给出一些链接) + +## 3. 测试和提交 PR + +先克隆文档仓库,本地通过 `npm run start` 和 `npm run build` 命令测试查看效果,确保可以正常浏览后提交 PR 即可。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute.md new file mode 100644 index 000000000..692df6ab8 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/contribute.md @@ -0,0 +1 @@ +# 贡献指南 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/git-guideline.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/git-guideline.md new file mode 100644 index 000000000..c475057df --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/contribute/git-guideline.md @@ -0,0 +1,132 @@ +# Git 提交指南 + +本文介绍了 Git 提交变更时需要注意的事项,如果拒绝接受本文的内容会导致提交的变更无法被接受。 + +## 1. 关于 issue + +在提交一个 issue 之前,请先查阅已经关闭的 issue ,也许在关闭的 issue 中已经存在合适的解决方案。 + +如果没有找到合适的方案,我们提供了4种模版在创建 issue 的时候使用。 + +- Bug Report : 发现了一个 Bug,可以通过 Bug Report 模版创建 issue 与我们联系。 +- Enhancement : 开发者对工具进行了增强,可以通过 Enhancement 模版创建 issue 来介绍增加的内容。 +- Feature Request : 在使用的过程中想要为工具增加某些新的特性或者功能,可以通过 Feature Request 模版创建 issue 来描述新特性。 +- Ask a Question : 如果有任何的疑问,可以通过 Ask a Question 模版来创建一个 issue 与我们联系。 + +在选择合适的模版后,只需要填写模版上的要求填写的内容即可。如果在创建 issue 的时候发现没有模版,或者模版内容为空,可以通过微信群,钉钉群或者邮件向我们反馈这个问题。 + +## 2. 关于 Git 分支 + +要向 kcl-lang 贡献代码,您必须拥有一个 GitHub 帐户,以便您可以将代码推送到您自己的分支并创建拉取请求。我们推荐参考 [Angular 规范](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines) 为您自己的分支命名。 +推荐的格式如下: + +``` +{type}-{a_short_description} +``` + +分支名称主要包括两个字段,并通过 “-” 分割。其中: + +- {type} : 当前分支内容的类型。 +- {a_short_description}: 一个简短的描述,介绍这个分支的主要内容。 + +e.g. 张三首先 Fork 仓库到自己账户下,然后创建对应名称 `zhangsan:fix-output-fmt-bug` 的分支(冒号之前是张三的账号),用于修复输出格式化 bug。 + +## 3. 关于 Git Commit + +我们参考 [Commitizen](https://github.com/commitizen/cz-cli) 书写 Commit Message。 + +``` +注: 如果直接使用 Commitizen 生成 Commit Message,需要注意因为 Commitizen +是开发人员管理 commit 的工具,与项目本身无关联,因此由 Commitizen 生成的中间产物 +(如: node_modules 文件目录)可能没有在项目 .gitignore 文件中。 + +您可以 git add {filename} 选择要提交的文件而忽视中间产物。 +或者您可以向 .gitignore 文件中添加如下内容而自动忽视中间产物: +# commitizen +package.json +package-lock.json +node_modules/* +``` + +如果手动编写 Commit Message,我们也建议采用 [Commitizen](https://github.com/commitizen/cz-cli) 的 commit message 格式。 + +``` +{type} ( {component_or_file} ) {a_short_description} + {a_longer_description} + BREAKING CHANGE: {breaking_change_description}. + {linked issue} +``` + +其中主要包括6个字段: + +- {type} : 当前 commit 对应的分支的类型。 +- {component_or_file}: 当前 commit 改动的模块或者文件的名称。 +- {a_short_description}: 简短的描述介绍 commit 中的内容。 +- {a_longer_description}: 详细的描述用来介绍 commit 中的内容。 +- {breaking_change_description}: 如果 commit 中包含破环兼容性的改动,需要对兼容性改动产生的影响进行介绍。 +- {linked issue}: 与当前这个 commit 关联的 issue。 + +其中 {breaking_change_description} 和 {linked issue} 如果 commit 中不包含破坏兼容性的改动和关联的 issue,可以省略。 + +e.g. 张三在分支 `zhangsan:fix-output-fmt-bug` 中创建的 commit。 + +``` + + fix(kcl-printer): fix an output format bug in kcl-printer + + There is an output format bug in kcl-printer because ..., + So, The calling of method "XXX" is replaced by "HHHH"..., + ... + + -- 如果没有破坏兼容性的改动和关联的 issue 可以省略下面内容。 + + BREAKING CHANGE: This change maybe cause ....... + + fix #123 + +``` + +## 4. 关于 pull request + +在提交一个 PR 之前,可能需要优先考虑以下几个问题: + +- 请先查阅已经关闭的 PR ,也许在已经关闭的 PR 中,可能存在已经完成的解决方案。 +- 我们建议在提交变更之前,提交一个对应的 issue 描述变更中将要解决的问题,并将变更对应的 PR 与 issue 关联。 +- 在向我们提交 PR 之后,请签署 [Contributor License Agreement (CLA)](#cla) ,如果拒绝签署,我们将无法接受 PR。 +- 请确保每次改动都创建了一个新的分支,并根据上文中提到的规范为分支命名。 +- 一次 PR 请不要超过两个 commit ,请将多余的 commit 通过 squash 压缩,并根据上文中提到的规范,编写 commit message 。 +- 我们提供了 [PR 模版](https://github.com/kcl-lang/.github/blob/main/.github/PULL_REQUEST_TEMPLATE.md),只需要添加模版中要求的内容即可,如果在创建PR时发现没有模版或者模版内容为空,可以通过微信群,钉钉群或者邮件向我们反馈这个问题。 + +我们建议PR的标题与分支名、commit message 风格保持一致: + +``` +{type} ( {component_name_or_file_name} ) :{a_short_description} +``` + +e.g. 张三为分支`fix/zhangsan/fix_output_fmt_bug`创建的PR名称。 + +``` +fix(kcl-printer): fix an output format bug in kcl-printer. +``` + +## 5. 目前 type 支持的类型 + +参考[Angular 规范](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines),type 支持类型的类型如下: + +``` +- feat: -- 添加了新的功能特性。 +- fix: -- 进行了 Bug 的修复。 +- docs: -- 进行了文档部分的修改。 +- style: -- 对代码格式的修改,并不影响代码的功能,如:删除多余空格,代码缩进等。 +- refactor: -- 在不改变代码功能的基础上对代码进行了的重构。 +- perf: -- 对代码进行了性能优化。 +- test: -- 添加或者调整已有的测试用例。 +- build: -- 对构建系统或者外部依赖库进行了调整。 +- ci: -- 调整了 CI 的配置文件或者脚本。 +- chore: -- 对源代码和测试文件之外其他部分的调整。 +- revert: -- 对 commit 进行回滚。 +``` + +## 6. Contributor License Agreement (CLA) + +在第一次向我们提交 PR 之后,在 PR 中的 CLA 检查将会失败并提示签署 CLA。您可以通过自己的账户之间在 PR 回复 "I have read the CLA Document and I hereby sign the CLA" 表示同意签署 CLA,然后手动重启失败的 CLA 检查 Action 即可。当 PR 被成功合并之后将会被锁定不能再修改。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/_category_.json new file mode 100644 index 000000000..e4cb1869c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "简介", + "position": 1 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/intro.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/intro.md new file mode 100644 index 000000000..af94bc332 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/intro.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 1 +--- + +# 社区 + +欢迎来到 KCL 开源社区,每个人的参与都是所有开源项目健康成长的动力!有很多方法可以参与开源。每个人都可以通过提交PR(Pull Request)来创建问题或修复 bug、改进文档或修改代码, + +可以查看[社区](https://github.com/kcl-lang/community)并加入我们。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/license.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/license.md new file mode 100644 index 000000000..fe1db435a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/license.md @@ -0,0 +1,211 @@ +--- +sidebar_position: 99 +--- + +# 许可 + +KCL 使用 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0): + +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The KCL Authors. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/support.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/support.md new file mode 100644 index 000000000..70ecd7e81 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/intro/support.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 1 +--- + +# 寻求帮助 + +KCL拥有一个由众多爱好者组成的开发者和用户社区。在此页面上,我们列出了您可以参与的KCL相关社区;有关其他在线和离线学习材料,请参阅本节的其他页面。 + +在加入 KCL 社区之前,请阅读[贡献者条款](https://www.contributor-covenant.org/version/2/0/code_of_conduct/),所有社区成员都需要遵守这些条款。 + +## 讨论 + +- 在 Github 上提交问题 +- 在 Github 讨论组中交流 +- 通过官方网站、Github、Twitter、微信和其他帐户获取 KCL 最新状态。可以查看[社区](https://github.com/kcl-lang/community)并加入我们。 + +## 新功能 + +请尽量避免提交新功能的拉取请求,我们可能已经有人在处理这些功能,或者这个功能已经是我们未来计划的一部分。总之,请在提交新功能之前与我们联系! diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/_category_.json new file mode 100644 index 000000000..bf01a0535 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "发布策略", + "position": 3 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/index.md new file mode 100644 index 000000000..a4a0bc3d1 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/index.md @@ -0,0 +1 @@ +# 发布策略 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/kcl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/kcl.md new file mode 100644 index 000000000..d9c919114 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/kcl.md @@ -0,0 +1,33 @@ +# KCL 发布策略 + +KCL 开发团队采用 [语义化版本](https://semver.org/lang/zh-CN/) 来简化管理。版本格式:主版本号.次版本号.修订号。版本号递增规则如下:主版本号对应不兼容的 API 修改,次版本号对应向下兼容的功能性新增,修订号对应向下兼容的问题修正。总体目标是每一个半月发布一个特性增强的次要版本,根据需要不定期发布其他版本的修订。 + +KCL 项目版本发布策略如下: + +- 主版本号:当进行重大的架构调整或者加入重大的新功能时,需要提升主版本号。对于 KCL 项目来说,目前的主版本号为 0。 +- 次版本号:当添加的功能和特性有较大的变化时,提升次版本号。目前的次版本号为 5,2023 年度会相继发布 0.5, 0.6, 0.7 版本。 +- 修订号:通过修复漏洞或者改进性能来更新程序时,会提升修订号,修订号从 0 开始计数以此加 1。 +- 发布周期:在未达到 v1.0.0 版本之前,计划每隔 3 个月发布一个新的次要版本。在此期间,需要持续收集用户反馈,并进行必要的修复和改进。 +- 发布流程:在发布新版本之前,需要进行严格的测试和审核,确保新版本的质量。封板并测试完成后,会在 Github 上发布新版本的源代码,二进制和镜像,并提供详细的文档和使用指南。 +- 版本支持:我们将对最新的版本提供长期支持,包括漏洞修复和安全更新。对于旧版本,我们将提供有限的支持,仅在必要时进行修复。 + +## 发布流程与规则 + +- 特性开发:main 分支主干开发,分支发布,block 用户使用的问题和严重的 bug, 安全隐患,高优先级解决,尽可能保持在一周内收敛,高于一般的功能研发。 +- 迭代周期:我们的迭代周期通常为 3 个月,即每 3 个月发布一个新的次要版本。 +- 版本规划:发版前两周产出 alpha 版本,前一周产出 beta 版本,alpha 版本仍可进行特性合并,beta 版本只合并错误修复,最终产出正式版本并打 tag 作为长期保存的 release 分支。 +- 发版计划:在每个发布周期开始时制定详细的发版计划(Github Milestone),包括发布日期、版本号、功能列表和测试计划等。需要尽可能地遵守发版计划,确保按时发布新版本。 +- 发布前测试:在发布新版本之前,需要进行全面的测试,包括单元测试、集成测试,模糊测试,压测,用户验收测试等。只有经过测试并无问题后,我们才会发布新版本。 +- 版本回滚:如果在发布后发现了严重的问题,需要立即回滚版本,并尽快修复问题。并通过邮件、社交媒体等渠道及时通知用户,并提供解决方案。 +- 发布文档:需要在发布时提供详细的文档,包括发布说明、更新日志、API 文档和使用指南等,帮助用户了解和使用新版本。在 KCL 中,我们统一在 KCL 网站进行维护。 +- 版本兼容性:在发布新版本时,需要尽可能保持兼容性,以确保用户无需进行过多的修改和适应。KCL 还没有达到 v1,暂时没有兼容性保证。KCL 的目标是尽可能少地进行重大更改,不应轻率地考虑对语言的更改,为了语言自身更好地演进和发展,一般认为更改具有重大好处时才会进行(较好地解决了目标场景的问题或者提升了绝大用户的使用体验)。对于可能引入兼容性问题的功能或变更,提供相应的提示和解决方案,同时会提供逐步升级的指南或提供自动迁移的工具,以帮助用户平滑地迁移到新版本。 + +## 一个 Feature 的生命周期 + +- 设计方案/文档:通过 Issue 回答清楚这个 feature 的动机是什么,它解决什么问题以及目标是什么,用户需求和用户故事是怎样的;这个 feature 做什么,如何做,难度怎样,需要多长时间,依赖项,需要做什么测试等。(Tips: 大的设计尽量拆分成小的设计,通过权衡和广泛的调研找到一个简单且可持续的解决方案,并且具备一定得到可扩展以适应未来的业务或技术变化,通过持续讨论和方案评审确定最终设计)。 +- 编写代码:通过高频小改动进行迭代、持续沟通和协作,提前设计单元测试、集成测试和 benchmark 等测试用例,确保编写代码 100% 测试覆盖,注释完整和逻辑清晰,并通过 Demo 演示持续收集反馈。 +- 文档撰写:在 [KCL 网站](https://kcl-lang.io) 中更新用户文档。 +- 测试和反馈:在发布功能之前,让一些同行/用户通过**随循文档**而不是口述来尝试和测试这些新功能。接收反馈并改进。 +- 发布和公告:撰写 Release Note, PR 文章,场景和新特性解读等以及渠道宣发等。 + +> 注:以上所有信息全是公开的,需要透出给所有社区研发者进行参与、讨论和贡献。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/roadmap.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/roadmap.md new file mode 100644 index 000000000..eff9b2e3a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/community/release-policy/roadmap.md @@ -0,0 +1,4 @@ +# 路线规划 + +- 2023 路线规划: https://github.com/kcl-lang/kcl/issues/29 +- 2024 路线规划: https://github.com/kcl-lang/kcl/issues/882 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/_category_.json new file mode 100644 index 000000000..1910abe40 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "参考手册", + "position": 5 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/_category_.json new file mode 100644 index 000000000..7839b7a27 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "备忘录", + "position": 10 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/index.md new file mode 100644 index 000000000..6bfb2e4c2 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/cheatsheets/index.md @@ -0,0 +1,5 @@ +# KCL 备忘录 + +![](/img/docs/reference/cheatsheets/cheatsheet.png) + +[Download PDF](https://github.com/kcl-lang/kcl-lang.io/blob/main/cheatsheet/cheatsheet.pdf) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/index.md new file mode 100644 index 000000000..9fd0c2763 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/index.md @@ -0,0 +1 @@ +# 学习 KCL diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/_category_.json new file mode 100644 index 000000000..6066c82bc --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "KCL", + "position": 1 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/_category_.json new file mode 100644 index 000000000..c01334437 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "代码实验室", + "position": 2 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/collaborative.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/collaborative.md new file mode 100644 index 000000000..883f48533 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/collaborative.md @@ -0,0 +1,345 @@ +--- +title: "使用配置操作分块编写配置" +linkTitle: "使用配置操作分块编写配置" +type: "docs" +weight: 2 +description: 使用配置操作分块编写配置 +sidebar_position: 3 +--- + +## 1. Introduction + +KCL 是一种简单易用的配置语言,用户可以简单地编写可重复使用的配置代码。 + +在这个教程中,我们将学习如何使用 KCL 配置操作(config operation)功能以协同的方式编写配置。 + +### 本节将会学习 + +1. 定义 schema 并组织项目目录。 +2. 通过KCL的配置操作功能创建多个环境配置。 +3. 配置编译参数和测试。 + +## 2. 定义 Schema 和 组织项目目录 + +### Schema 定义 + +假设我们想定义具有某些属性的服务器配置,我们可以通过创建一个 `server.k` 文件来创建一个简单的配置,我们可以填写以下代码来定义服务器配置的可重用模式: + +```python +import units + +type Unit = units.NumberMultiplier + +schema Server: + replicas: int = 1 + image: str + resource: Resource = {} + mainContainer: Main = {} + labels?: {str:str} + annotations?: {str:str} + +schema Main: + name: str = "main" + command?: [str] + args?: [str] + ports?: [Port] + +schema Resource: + cpu?: int = 1 + memory?: Unit = 1024Mi + disk?: Unit = 10Gi + +schema Port: + name?: str + protocol: "HTTP" | "TCP" + port: 80 | 443 + targetPort: int + + check: + targetPort > 1024, "targetPort must be larger than 1024" +``` + +在上面的代码中,我们定义了一个名为 Server 的 schema,该 schema 表示用户将要编写的配置类型,其中包含一些基本类型属性(例如`replicas`、`image` 等)和一些复合类型属性(例如 `resource`、`main` 等)。除了一些在 [schema codelab](./schema.md)中提到的基本类型之外,我们可以看到上面的代码中有两种类型 `Unit` 和 `units.NumberMultiplier`。其中,`units.NumberMultiplier` 表示 KCL 数字单位类型,意味着可以在 KCL 数字后添加自然单位或二进制单位,例如 `1K` 表示 `1000`,`1Ki` 表示 `1024`。 `Unit` 是 `units.NumberMultiplier` 的类型别名,用于简化类型注释的编写。 + +### 项目目录 + +为了完成协同的配置的开发,我们首先需要一个配置项目,其中包含测试应用程序的配置以及不同环境的差异化配置,因此我们正在创建以下项目目录: + +``` +. +├── appops +│ └── test_app +│ ├── base +│ │ └── base.k +│ ├── dev +│ │ ├── ci-test +│ │ │ └── stdout.golden.yaml +│ │ ├── kcl.yaml +│ │ └── main.k +│ └── prod +│ ├── ci-test +│ │ └── stdout.golden.yaml +│ ├── kcl.yaml +│ └── main.k +├── kcl.mod +└── pkg + └── sever.k +``` + +该项目目录主要包含三个部分: + +- `kcl.mod`:用于标识KCL项目的根目录的文件。 +- `pkg`:不同应用程序配置所共用的 `Server Schema` 结构。 +- `appops`:不同应用程序的 Server 配置,目前仅包含一个名为 `test_app` 的应用程序。 + - `base`:供所有环境使用的应用程序通用配置。 + - `dev`:供开发环境使用的应用程序配置。 + - `prod`:供生产环境使用的应用程序配置。 + +后续章节将会介绍`base.k`、`main.k`、`kcl.yaml` 和 `ci-test/stdout.golden.yaml` 的含义。 + +## 3. 通过 KCL 配置操作功能创建多个环境配置 + +### 创建基线配置 + +在组织好项目目录和基本的服务器配置模型之后,我们可以编写用户应用程序的配置。我们可以创建自己的测试应用程序文件夹 `test_app`,并将其放置在应用程序配置文件夹 `appops` 中。 + +对于应用程序的配置,我们通常将其分为基本配置和多个环境的差异化配置并进行合并。通过 KCL 的配置合并功能,我们可以轻松实现这一点。假设我们有开发环境和生产环境的两个配置,我们可以创建三个文件夹:`base`、`dev` 和 `prod` 分别存储基线、开发环境和生产环境的配置。首先,我们编写 `base/base.k` 的配置: + +```python +import pkg + +server: pkg.Server { + # 设置镜像的值为 "nginx:1.14.2" + image = "nginx:1.14.2" + # 添加 app label + labels.app = "test_app" + # 添加一个mainContainer配置,它的端口是 [{protocol = "HTTP", port = 80, targetPort = 1100}] + mainContainer.ports = [{ + protocol = "HTTP" + port = 80 + targetPort = 1100 + }] +} +``` + +正如上述代码中所示,我们使用 `import` 关键字在 `base.k` 中导入放置在 `pkg` 下的 `Server` schema,并使用它实例化一个名为`server` 的配置,在其中将 `image` 属性设置为 `"nginx:1.14.2"`,并添加一个带有值为 `test_app` 的标签 `app`。此外,我们还在 `ports` 属性中添加了主容器 `mainContainer` 的配置,其值为 `[{protocol = "HTTP", port = 80, targetPort = 1100}]`。 + +KCL 命令: + +```bash +kcl appops/test_app/base/base.k +``` + +输出: + +```yaml +server: + replicas: 1 + image: nginx:1.14.2 + resource: + cpu: 1 + memory: 1073741824 + disk: 10737418240 + mainContainer: + name: main + ports: + - protocol: HTTP + port: 80 + targetPort: 1100 + labels: + app: test_app +``` + +当前,我们已经有了一个基线配置。 + +### 创建多重环境配置 + +接下来我们将配置一个差异化的多环境配置。首先假设我们想在开发环境中使用自己的临时镜像 `nginx:1.14.2-dev`,然后使用它来覆盖基准中的服务器配置,我们可以在 `dev/main.k` 中编写以下配置: + +```python +import pkg + +server: pkg.Server { + # 覆盖 base 配置中的声明的镜像 + image = "nginx:1.14.2-dev" +} +``` + +KCL 命令: + +```bash +kcl appops/test_app/base/base.k appops/test_app/dev/main.k +``` + +输出: + +```yaml +server: + replicas: 1 + image: nginx:1.14.2-dev + resource: + cpu: 1 + memory: 1073741824 + disk: 10737418240 + mainContainer: + name: main + ports: + - protocol: HTTP + port: 80 + targetPort: 1100 + labels: + app: test_app +``` + +可以看出输出的 YAML 文件的 `image` 字段被覆盖为 `nginx:1.14.2-dev`。假设我们还想将一个具有键为 `env`,值为 `dev` 的标签添加到 `dev` 环境中,我们将以下代码添加到 `dev/main.k` 中: + +```python +import pkg + +server: pkg.Server { + # 覆盖 base 配置中的声明的镜像 + image = "nginx:1.14.2-dev" + # 将新标签 env 合并到 base 标签中 + labels.env = "dev" +} +``` + +KCL 命令: + +```bash +kcl appops/test_app/base/base.k appops/test_app/dev/main.k +``` + +```yaml +server: + replicas: 1 + image: nginx:1.14.2-dev + resource: + cpu: 1 + memory: 1073741824 + disk: 10737418240 + mainContainer: + name: main + ports: + - protocol: HTTP + port: 80 + targetPort: 1100 + labels: + app: test_app + env: dev +``` + +可以看到输出的 YAML 文件的 `labels` 字段中有两个标签。 + +此外,我们还可以使用 `+=` 运算符将新值添加到列表类型属性中,例如在基准环境中的 `mainContainer.ports` 配置,继续修改 `dev/main.k` 中的代码: + +```python +import pkg + +server: pkg.Server { + # 覆盖 base 配置中的声明的镜像 + image = "nginx:1.14.2-dev" + # 将新标签 env 合并到 base 标签中 + labels.env = "dev" + # 在 base ports配置中添加一个 port + mainContainer.ports += [{ + protocol = "TCP" + port = 443 + targetPort = 1100 + }] +} +``` + +KCL 命令: + +```bash +kcl appops/test_app/base/base.k appops/test_app/dev/main.k +``` + +输出: + +```yaml +server: + replicas: 1 + image: nginx:1.14.2-dev + resource: + cpu: 1 + memory: 1073741824 + disk: 10737418240 + mainContainer: + name: main + ports: + - protocol: HTTP + port: 80 + targetPort: 1100 + - protocol: TCP + port: 443 + targetPort: 1100 + labels: + app: test_app + env: dev +``` + +使用相同的方法,我们可以构建生产配置,在 `dev/main.k` 文件中编写代码,并为其添加标签。 + +```python +import pkg + +server: pkg.Server { + # 将新标签 env 合并到 base 标签中 + labels.env = "prod" +} +``` + +KCL 命令: + +```bash +kcl appops/test_app/base/base.k appops/test_app/prod/main.k +``` + +输出: + +```yaml +server: + replicas: 1 + image: nginx:1.14.2 + resource: + cpu: 1 + memory: 1073741824 + disk: 10737418240 + mainContainer: + name: main + ports: + - protocol: HTTP + port: 80 + targetPort: 1100 + labels: + app: test_app + env: prod +``` + +## 4. 配置编译参数和测试 + +在前面的章节中,我们通过代码构建了一个多环境配置。可以看出不同环境的 KCL 命令行编译参数相似,因此我们可以将这些编译参数配置到一个文件中,并将其输入到 KCL 命令行中进行调用。请将以下代码配置在 `dev/kcl.yaml`中: + +```yaml +kcl_cli_configs: + files: + - ../base/base.k + - main.k + output: ./ci-test/stdout.golden.yaml +``` + +然后我们可以使用以下命令在开发环境中编译配置: + +```bash +cd appops/test_app/dev && kcl -Y ./kcl.yaml +``` + +此外,我们已经在 `dev/kcl.yaml` 中配置了 `output` 字段,以将 YAML 输出到文件,以便进行后续配置分发或测试。您可以通过遍历每个环境中的 `kcl.yaml` 构建,并将其与 `./ci-test/stdout.golden.yaml` 进行比较,可以验证应用程序的配置是否符合预期。 + +## 5. 最后 + +恭喜! + +我们已经完成了关于 KCL 的第三课。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/index.md new file mode 100644 index 000000000..123c0878c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/index.md @@ -0,0 +1 @@ +# 代码实验室 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/schema.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/schema.md new file mode 100644 index 000000000..4e82619c5 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/schema.md @@ -0,0 +1,817 @@ +--- +title: "使用 KCL Schema 编写复杂配置" +linkTitle: "使用 KCL Schema 编写复杂配置" +type: "docs" +weight: 2 +description: 使用 KCL Schema 编写复杂配置 +sidebar_position: 2 +--- + +## 1. 介绍 + +KCL 是一种简单易用的配置语言,用户可以简单地编写可重用的配置代码。 + +在本节教程中,我们将学习如何使用 KCL 编写定制配置,这样我们就可以定义一个架构并以协作方式编写配置。 + +### 本节将会学习 + +1. 定义一个简单的 schema +2. 为 schema 字段设置默认的不可变值 +3. 基于简单的 schema 创建配置 +4. 在 schema 中编写复杂的逻辑 +5. 通过 schema 的组合创建新的 schema +6. 使用 dict/map 创建具有深度嵌套 schema 的配置 +7. 通过 schema 继承创建新的 schema +8. 通过多个 mixin schema 创建新的 schema +9. 声明 schema 验证规则 +10. 配置 schema 的输出布局 +11. 共享和重用 schema + +## 2. 编写简单的 Schema + +假设我们希望定义一个具有特定属性的工作负载,我们可以通过创建一个 `my_config.k` 文件来创建一个简单的配置。我们可以按以下方式填写下面的代码,定义一个可重复使用的部署配置的 schema: + +```python +schema Deployment: + name: str + cpu: int + memory: int + image: str + service: str + replica: int + command: [str] + labels: {str:str} +``` + +在上述代码中,`cpu` 和 `memory` 被定义为 int 值;`name`、`image` 和 `service` 是字符串;`command` 是由字符串构成的列表;`labels` 是字典类型,其键和值的类型均为字符串。 + +另外,每个属性都**必须**被赋予非 None 值作为 schema 实例,除非它被标记问号 **?** 而作为可选参数。 + +```python +schema Deployment: + name: str + cpu: int + memory: int + image: str + service: str + replica: int + command: [str] + labels?: {str:str} # labels 是一个可选的参数 +``` + +当存在继承关系时: + +- 如果在基 schema 中该属性为可选(optional)参数,则在子 schema 中它应该是可选的(optional)或必需的(required)。 +- 如果在基 schema 中该属性为必需(required)属性,则在子 schema 中它需要是必需的(required)。 + +## 3. Enhance Schema as Needed + +Suppose we need to set default values to service and replica, we can make them as below: + +```python +schema Deployment: + name: str + cpu: int + memory: int + image: str + service: str = "my-service" # defaulting + replica: int = 1 # defaulting + command: [str] + labels?: {str:str} # labels is an optional attribute +``` + +And then we can set the service type annotation as the string literal type to make it immutable: + +```python +schema Deployment: + name: str + cpu: int + memory: int + image: str + service: "my-service" = "my-service" + replica: int = 1 + command: [str] + labels?: {str:str} +``` + +In the schema, type hint is a `must`, for example we can define cpu as `cpu: int`. + +Specially, we can define a string-interface dict as `{str:}`, and in case we want to define an object or interface, just define as `{:}`. + +## 4. 基于简单 Schema 创建配置 + +现在我们有了一个简单的 schema 定义,我们可以用它来定义配置: + +```python +nginx = Deployment { + name = "my-nginx" + cpu = 256 + memory = 512 + image = "nginx:1.14.2" + command = ["nginx"] + labels = { + run = "my-nginx" + env = "pre-prod" + } +} +``` + +使用以下 KCL 命令运行,我们应该能够看到生成的 yaml 文件作为输出,如下所示: + +KCL 命令: + +```python + kcl my_config.k +``` + +标准输出: + +```yaml +nginx: + name: my-nginx + cpu: 256 + memory: 512 + image: nginx:1.14.2 + service: my-service + replica: 1 + command: + - nginx + labels: + run: my-nginx + env: pre-prod +``` + +> 有关集合数据类型和块的更多详细信息,请查看手册和规范。 + +此外,**配置选择器表达式**(config selector expressions)可以用于初始化 schema 实例,我们可以忽略配置表达式中行末的逗号。 + +```python +nginx = Deployment { + name = "my-nginx" + cpu = 256 + memory = 512 + image = "nginx:1.14.2" + command = ["nginx"] # 忽略行尾的逗号 + labels.run = "my-nginx" # schema 中的字典变量可以使用选择器表达式 + labels.env = "pre-prod" # schema 中的字典变量可以使用选择器表达式 +} +``` + +## 5. 在 Schema 中编写更为复杂的逻辑 + +假设我们有一些schema逻辑,我们可以将它包装进 schema 中: + +```python +schema Deployment[priority]: + name: str + image: str + service: "my-service" = "my-service" + replica: int = 1 + command: [str] + labels?: {str:str} + + _cpu = 2048 + if priority == 1: + _cpu = 256 + elif priority == 2: + _cpu = 512 + elif priority == 3: + _cpu = 1024 + else: + _cpu = 2048 + + cpu: int = _cpu + memory: int = _cpu * 2 +``` + +现在,我们可以通过创建 schema 实例来定义配置,并将优先级作为参数传递给模式: + +```python +nginx = Deployment(priority=2) { + name = "my-nginx" + image = "nginx:1.14.2" + command = ["nginx"] + labels.run = "my-nginx" + labels.env = "pre-prod" +} +``` + +使用以下 KCL 命令运行,我们应该能够看到生成的 yaml 文件作为输出,如下所示: + +KCL 命令: + +```python +kcl my_config.k +``` + +标准输出: + +```yaml +nginx: + name: my-nginx + cpu: 512 + memory: 1024 + image: nginx:1.14.2 + service: my-service + replica: 1 + command: + - nginx + labels: + run: my-nginx + env: pre-prod +``` + +## 6. 通过 Schema 组合创建新 Schema + +现在我们想要定义一个详细的 schema,包括服务(service)和卷(volumes),我们可以按以下方式进行操作: + +```python +schema Deployment[priority]: + name: str + volumes?: [Volume] + image: str + service?: Service + replica: int = 1 + command: [str] + labels?: {str:str} + + if priority == 1: + _cpu = 256 + elif priority == 2: + _cpu = 512 + elif priority == 3: + _cpu = 1024 + else: + _cpu = 2048 + + cpu: int = _cpu + memory: int = _cpu * 2 + +schema Port: + name: str + protocol: str + port: int + targetPort: int + +schema Service: + name: "my-service" = "my-service" + ports: [Port] + +schema Volume: + name: str + mountPath: str + hostPath: str +``` + +在这种情况下,Deployment 由 Service 和一系列 Volume 组成,而 Service 又由一系列 Port 组成。 + +## 7. 使用 dict/map 创建具有深度嵌套 schema 的配置 + +现在我们有一个新的 Deployment schema,但我们可能会注意到,它包含多层嵌套的结构,在复杂的结构定义中,这是非常常见的,我们通常必须编写命令式组装代码来生成最终结构。 + +使用 KCL,我们可以使用简单的字典声明创建配置,并具有完整的 schema 初始化和验证功能。例如,我们可以按照以下方式使用新的 Deployment schema简单地配置 nginx: + +```python +nginx = Deployment(priority=2) { + name = "my-nginx" + image = "nginx:1.14.2" + volumes = [Volume { + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + command = ["nginx"] + labels.run = "my-nginx" + labels.env = "pre-prod" + service.ports = [Port { + name = "http" + protocol = "TCP" + port = 80 + targetPort = 9376 + }] +} +``` + +使用以下 KCL 命令运行,我们应该能够看到生成的 yaml 文件作为输出,如下所示: + +KCL 命令: + +```python +kcl my_config.k +``` + +标准输出: + +```yaml +nginx: + name: my-nginx + cpu: 512 + memory: 1024 + volumes: + - name: mydir + mountPath: /test-pd + hostPath: /data + image: nginx:1.14.2 + service: + name: my-service + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9376 + replica: 1 + command: + - nginx + labels: + run: my-nginx + env: pre-prod +``` + +请注意,我们用于定义 Deployment 配置的字典必须与 schema 定义对齐,否则我们将会得到一个错误。例如,假设我们将服务端口的类型定义错误如下: + +```python +nginx = Deployment(priority=2) { + name = "my-nginx" + image = "nginx:1.14.2" + volumes = [Volume { + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + command = ["nginx"] + labels.run = "my-nginx" + labels.env = "pre-prod" + service.ports = [Port { + name = "http" + protocol = "TCP" + port = [80] # 错误的数据类型,试图将 List 分配给 int + targetPort = 9376 + }] +} +``` + +使用以下 KCL 命令运行,我们应该能够看到生成的 yaml 文件作为输出,如下所示: + +KCL 命令: + +```python +kcl my_config.k +``` + +标准错误输出: + +``` +The type got is inconsistent with the type expected: expect int, got [int(80)] +``` + +## 8. 声明 Schema 验证规则 + +现在我们已经看到了一个复杂的 schema,在其中每个字段都有一个类型提示,以使其更加不容错(error-prone)。 + +但是这还不够好,我们希望为我们的 schema 支持更多的增强验证,以便尽快发现 schema 和配置中的代码错误。许多验证规则,如 None 类型检查、范围检查、值检查、长度检查、正则表达式匹配、枚举检查已经被添加或陆续添加进来。以下是一段代码示例: + +```python +import regex + +schema Deployment[priority]: + name: str + volumes?: [Volume] + image: str + service?: Service + replica: int = 1 + command: [str] + labels?: {str:str} + + if priority == 1: + _cpu = 256 + elif priority == 2: + _cpu = 512 + elif priority == 3: + _cpu = 1024 + else: + _cpu = 2048 + + cpu: int = _cpu + memory: int = _cpu * 2 + + check: + multiplyof(cpu, 256), "cpu must be a multiplier of 256" + regex.match(image, "^[a-zA-Z]+:\d+\.\d+\.\d+$"), "image name should be like 'nginx:1.14.2'" + 1 <= replica < 100, "replica should be in range (1, 100)" + len(labels) >= 2 if labels, "the length of labels should be large or equal to 2" + "env" in labels, "'env' must be in labels" + len(command) > 0, "the command list should be non-empty" + +schema Port: + name: str + protocol: str + port: int + targetPort: int + + check: + port in [80, 443], "we can only expose 80 and 443 port" + protocol in ["HTTP", "TCP"], "protocol must be either HTTP or TCP" + 1024 < targetPort, "targetPort must be larger than 1024" + +schema Service: + name: "my-service" = "my-service" + ports: [Port] + + check: + len(ports) > 0, "ports list must be non-empty" + +schema Volume: + name: str + mountPath: str + hostPath: str +``` + +由于schema定义的属性默认是**必需的**(required),因此可以省略判断变量不能为 None/Undefined 的验证。 + +```python +schema Volume: + name: str + mountPath: str + hostPath: str +``` + +现在我们可以基于新的 schema 编写配置,并及时暴露配置错误。例如,使用以下无效的配置: + +```python +nginx = Deployment(priority=2) { + name = "my-nginx" + image = "nginx:1142" # 镜像值不匹配正则表达式 + volumes = [Volume { + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + command = ["nginx"] + labels.run = "my-nginx" + labels.env = "pre-prod" + service.ports = [Port { + name = "http" + protocol = "TCP" + port = 80 + targetPort = 9376 + }] +} +``` + +每个字段都是类型有效的,但镜像名无效。 + +运行 KCL,我们将看到如下错误信息: + +KCL 命令: + +```python +kcl my_config.k +``` + +标准错误输出: + +``` +Schema check is failed to check condition: regex.match(image, "^[a-zA-Z]+:\d+\.\d+\.\d+$"), "image name should be like 'nginx:1.14.2'" +``` + +> KCL 的验证功能涵盖了 Openapi 定义的验证,因此我们可以通过 KCL 编写任何 API 验证。 + +## 9. 通过 Schema 继承创建新 Schema + +现在,我们拥有了一个稳定的部署 schema 定义,可以用它来声明配置。 + +通常,部署 schema 将被用于多个场景中。我们可以直接使用 schema 在不同的用例中声明配置(见上文的部分),或者我们可以通过继承生成一个更具体的 schema 定义。 + +例如,我们可以使用部署 schema 作为基础,来定义 nginx 的基本 schema,并在每个场景中扩展定义。在这种情况下,我们定义了一些常用的属性。请注意,我们使用“final”关键字将名称标记为不可变,以防止被覆盖。 + +```python +schema Nginx(Deployment): + """ A base nginx schema """ + name: "my-nginx" = "my-nginx" + image: str = "nginx:1.14.2" + replica: int = 3 + command: [str] = ["nginx"] + +schema NginxProd(Nginx): + """ A prod nginx schema with stable configurations """ + volumes: [Volume] = [{ + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + """ A volume mapped to host path """ + service: Service = { + ports = [{ + name = "http" + protocol = "TCP" + port = 80 + targetPort = 9376 + }] + } + """ An 80 port to target backend server """ +``` + +现在我们有了一些 nginx 的静态配置。建议将我们认为是静态的配置声明在那里,并将更多的动态配置放在下面: + +```python +nginx = Nginx { + labels.run = "my-nginx" + labels.env = "pre-prod" +} +``` + +```python +nginx = NginxProd { + labels.run = "my-nginx" + labels.env = "pre-prod" +} +``` + +现在,我们只需要通过运行时标签值 “prod” 来简单定义 不那么静态的 nginx 生产环境配置。 + +实际上,在某些复杂情况下,我们可以将所有配置分为基本配置、业务配置和环境配置定义,并基于此实现团队成员之间的协作。 + +使用以下 KCL 命令运行,我们应该能够看到生成的 yaml 文件作为输出,如下所示: + +KCL 命令: + +```python +kcl prod_config.k +``` + +标准输出: + +```yaml +nginx: + name: my-nginx + cpu: 512 + memory: 1024 + volumes: + - name: mydir + mountPath: /test-pd + hostPath: /data + image: nginx:1.14.2 + service: + name: my-service + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9376 + replica: 3 + command: + - nginx + labels: + run: my-nginx + env: pre-prod +``` + +## 10. Create New Schema by Multiple Protocol and Mixin Schemas Inheritance + +现在,我们可以通过 Deployment schema 完成服务器配置的声明。 + +然而,通常实际情况更为复杂,部署可能有各种可选变量附件。 + +例如,我们想要在现有 schema 中支持声明持久卷,作为可重用的 Kubernetes schema。在这种情况下,我们可以通过以下 `mixin` 和 `protocal` 进行包装: + +```python +import k8spkg.api.core.v1 + +protocol PVCProtocol: + pvc?: {str:} + +mixin PersistentVolumeClaimMixin for PVCProtocol: + """ + PersistentVolumeClaim (PVC) sample: + Link: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims + """ + + # Mix in a new attribute `kubernetesPVC` + kubernetesPVC?: v1.PersistentVolumeClaim + + if pvc: + kubernetesPVC = v1.PersistentVolumeClaim { + metadata.name = pvc.name + metadata.labels = pvc.labels + spec = { + accessModes = pvc.accessModes + resources = pvc.resources + storageClassName = pvc.storageClassName + } + } +``` + +有了 PersistentVolumeClaimMixin,我们使用清晰的用户界面(user interface)定义了一个 PVC schema,并使用 Kubernetes PVC 作为实现。然后,我们可以使用 Deployment schema 和 PVC mixin schema 定义一个 server schema。 + +```python +schema Server(Deployment): + mixin [PersistentVolumeClaimMixin] + pvc?: {str:} + """ pvc user interface data defined by PersistentVolumeClaimMixin """ +``` + +在 Server schema 中,Deployment schema 是基础 schema,而 PersistentVolumeClaimMixin 是一个可选附加项,其用户界面数据为`pvc?:{str:}`。 + +请注意,mixin 通常用于向宿主 schema 添加新属性,或修改宿主 schema 的现有属性。因此,mixin 可以使用宿主 schema 中的属性。由于其被设计为可重用,因此我们需要一个额外的协议来限制 mixin 中宿主 schema 中属性的名称和类型。 + +现在,如果我们想要使用 PVC 进行部署,只需声明用户界面: + +```python +server = Server { + name = "my-nginx" + image = "nginx:1.14.2" + volumes = [Volume { + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + command = ["nginx"] + labels = { + run = "my-nginx" + env = "pre-prod" + } + service.ports = [Port { + name = "http" + protocol = "TCP" + port = 80 + targetPort = 9376 + }] + pvc = { + name = "my_pvc" + accessModes = ["ReadWriteOnce"] + resources.requests.storage = "8Gi" + storageClassName = "slow" + } +} +``` + +使用以下 KCL 命令运行,我们应该能够看到生成的 yaml 文件作为输出,如下所示: + +KCL 命令: + +```python +kcl server.k +``` + +标准输出: + +```yaml +server: + name: my-nginx + cpu: 512 + memory: 1024 + volumes: + - name: mydir + mountPath: /test-pd + hostPath: /data + image: nginx:1.14.2 + service: + name: my-service + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9376 + replica: 1 + command: + - nginx + labels: + run: my-nginx + env: pre-prod + pvc: + name: my_pvc + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 8Gi + storageClassName: slow +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: my_pvc +spec: + accessModes: + - ReadWriteOnce + storageClassName: slow + resources: + requests: + storage: 8Gi +``` + +如果我们不需要持久卷,只需删除 pvc 配置块。 + +## 11. 共享和重用 Schema + +可以通过导入来共享 Server schema,我们只需要将代码与 KCL 一起打包即可。 + +```python +import pkg + +server = pkg.Server { + name = "my-nginx" + image = "nginx:1.14.2" + volumes = [Volume { + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + command = ["nginx"] + labels.run = "my-nginx" + labels.env = "pre-prod" + service.ports = [Port { + name = "http" + protocol = "TCP" + port = 80 + targetPort = 9376 + }] +} +``` + +另一个关于共享代码的技巧是:在同一包下的模块不需要相互导入。 + +假设我们在 pkg 中有如下 models: + +``` +pkg/ + - deploy.k + - server.k + - pvc.k +``` + +在 `server.k` 中,我们可以只使用 `deploy.k` 中的 Deployment schema 和 `pvc.k` 中的 pvc schema 而无需导入: + +```python +# 无需 import +schema Server(Deployment): + mixin [PersistentVolumeClaimMixin] + pvc?: {str:} + """ pvc user interface data defined by PersistentVolumeClaimMixin """ +``` + +然后用户必须导入 pkg 才能作为一个整体使用它: + +```python +import pkg + +server = pkg.Server { + name = "my-nginx" + image = "nginx:1.14.2" + volumes = [pkg.Volume { + name = "mydir" + mountPath = "/test-pd" + hostPath = "/data" + }] + command = ["nginx"] + labels = { + run = "my-nginx" + env = "pre-prod" + } + service.ports = [pkg.Port { + name = "http" + protocol = "TCP" + port = 80 + targetPort = 9376 + }] +} +``` + +运行 KCL 命令: + +```python +kcl pkg_server.k +``` + +Output: + +```yaml +server: + name: my-nginx + cpu: 512 + memory: 1024 + volumes: + - name: mydir + mountPath: /test-pd + hostPath: /data + image: nginx:1.14.2 + service: + name: my-service + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 9376 + replica: 1 + command: + - nginx + labels: + run: my-nginx + env: pre-prod +``` + +## 12. 最后 + +恭喜! + +我们已经完成了 KCL 的第二节课。我们使用 KCL 来替换我们的 key-value 文本文件,以便获得更好的可编程性。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/simple.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/simple.md new file mode 100644 index 000000000..32ad2612b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/codelab/simple.md @@ -0,0 +1,495 @@ +--- +title: "使用 KCL 编写简单配置" +linkTitle: "使用 KCL 编写简单配置" +type: "docs" +weight: 2 +description: 使用 KCL 编写简单配置 +sidebar_position: 1 +--- + +## 1. 介绍 + +KCL 是一种简单易用的配置语言,用户可以简单地编写可重用的配置代码。 + +在这个第一个教程中,我们将学习如何使用 KCL 编写一个简单的配置。 + +学习这个代码实验只需要基本的编程知识,如果你有 Python 经验,将会更容易上手。 + +### 本节将会学习 + +1. 用一种可编程的方式编写简单的 key-value 配置 +2. 使用 KCL 编写简单的逻辑 +3. 使用 KCL 编写集合(collections) +4. 使用 KCL 代码进行测试和调试 +5. 在 KCL 代码中使用内置(built-in)支持 +6. 共享和重用 KCL 代码 +7. 使用动态输入参数编写配置 + +## 2. 编写Key-Value键值对 + +通过创建 `my_config.k` 来生成一个简单的配置,我们可以填充下面的代码,并且不需要严格的格式描述部署的配置。 + +```python +cpu = 256 +memory = 512 +image = "nginx:1.14.2" +service = "my-service" +``` + +在上述代码中,cpu 和 memory 被声明为 int 类型的值,而 image 和 service 被声明为字符串字面值。 + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +KCL 命令: + +```bash +kcl my_config.k +``` + +标准输出: + +```yaml +cpu: 256 +memory: 512 +image: nginx:1.14.2 +service: my-service +``` + +可导出变量(exported variable)默认情况下是不可变的,一旦声明,就不能在其他地方修改它。 + +## 3. 编写简单逻辑 + +有时候我们想在配置中编写一些逻辑,那么我们就可以使用: + +- 以 `_` 开头的非导出可变变量(mutable and non-exported variable) +- if-else 语句 + +非导出变量表示它不会出现在输出的 YAML 中,且它可以被多次赋值。 + +这是一个示例,显示如何根据条件调整资源。 + +KCL 命令: + +```python +kcl my_config.k +``` + +```python +_priority = 1 # 非导出可变变量 +_cpu = 256 # 非导出可变变量 + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 + +cpu = _cpu +memory = _cpu * 2 +image = "nginx:1.14.2" +service = "my-service" +``` + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +```python +kcl my_config.k +``` + +标准输出: + +```yaml +cpu: 256 +memory: 512 +image: nginx:1.14.2 +service: my-service +``` + +.. 注意:: +KCL 对运算符和字符串成员函数有丰富的支持,请阅读手册和规范以了解更多细节。 + +## 4. 编写集合 + +我们可以使用集合来表示复杂的数据类型。已支持的集合类型有: + +- list +- dict + +```python +_priority = 1 # 非导出可变变量 +_cpu = 256 # 非导出可变变量 + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 + +cpu = _cpu +memory = _cpu * 2 +command = ["nginx"] # 列表 +labels = {run = "my-nginx"} # a dict +image = "nginx:1.14.2" +service = "my-service" +``` + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +KCL 命令: + +```bash +kcl my_config.k +``` + +标准输出: + +```yaml +cpu: 512 +memory: 1024 +command: + - nginx +labels: + run: my-nginx +image: nginx:1.14.2 +service: my-service +``` + +> 有关集合数据类型和成员函数的更多信息,请查阅手册和规范。 + +## 5. 在集合中添加元素 + +我们可以将逻辑表达式、推导式、切片、联合类型等特性组合起来,动态地将元素添加到集合中。 + +```python +_priority = 1 # 非导出可变变量 +_cpu = 256 # 非导出可变变量 +_env = "pre-prod" + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 + +cpu = _cpu +memory = _cpu * 2 +_command = ["nginx"] # 列表 +_command = _command + ["-f", "file"] # 使用 + 运算符将元素附加到命令中以连接两个列表 +command = [c.lower() for c in _command] # # 将列表中的每个元素转为小写 +_labels = { + run = "my-nginx" + if _env: + env = _env # 当 _env 不是 None/Undefined 或为空时使用 if 表达式添加一个字典键值对 +} # 字典 +labels = _labels +image = "nginx:1.14.2" +service = "my-service" +``` + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +```python +kcl my_config.k +``` + +标准输出: + +```yaml +cpu: 256 +memory: 512 +command: + - nginx + - -f + - file +labels: + run: my-nginx +image: nginx:1.14.2 +service: my-service +``` + +## 6. 编写断言 + +为了使代码可测试且健壮,我们可以使用断言(assertions)验证配置数据。 + +```python +_priority = 1 # 非导出可变变量 +_cpu = 256 # 非导出可变变量 + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 + +cpu = _cpu +memory = _cpu * 2 +command = ["nginx"] # 列表 +labels = {run = "my-nginx"} # 字典 +image = "nginx:1.14.2" +service = "my-service" +assert "env" in labels, "env label is a must" +assert cpu >= 256, "cpu cannot be less than 256" +``` + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +```bash +kcl my_config.k +``` + +标准错误输出: + +```bash +Assertion failure: env label is a must. +``` + +将 env:pre-prod 对添加到标签中后,我们将得到如下输出: + +```yaml +cpu: 512 +memory: 1024 +command: + - nginx +labels: + run: my-nginx + env: pre-prod +image: nginx:1.14.2 +service: my-service +``` + +## 7. 使用方便的内置支持 + +更重要的是,我们可以使用内置函数来帮助我们调试或简化编码。 + +```python +_priority = 1 # 非导出可变变量 +_cpu = 256 # 非导出可变变量 + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 + +_name = "nginx" +# exported variables +cpu = _cpu +memory = _cpu * 2 +command = [_name] # 列表 +labels = { + run = "my-{}".format(_name) + env = "pre-prod" +} # a dict +image = "{}:1.14.2".format(_name) # 字符串格式 +service = "my-service" + +# debugging +print(labels) # 通过打印调式 + +# test +assert len(labels) > 0, "labels can't be empty" # 使用 len() 得到列表长度 +assert "env" in labels, "env label is a must" +assert cpu >= 256, "cpu cannot be less than 256" +``` + +此示例展示了我们如何使用 `format()`、`len()`、`print()` 函数来帮助自定义配置。 + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +KCL 命令: + +```bash +kcl my_config.k +``` + +标准输出: + +```yaml +cpu: 512 +memory: 1024 +command: + - nginx +labels: + run: my-nginx + env: pre-prod +image: nginx:1.14.2 +service: my-service +run: my-nginx +env: pre-prod +``` + +注意:更多的内置函数和模块可以在 spec/module 目录中查看。 + +## 8. 重用另一个模块的变量 + +为了使我们的代码得到良好的组织,我们可以将代码简单地分为 `my_config.k` 和 `my_config_test.k` 两个文件。 + +在 `my_config.k` 中定义配置数据: + +```python +_priority = 1 # 非导出可变变量 +_cpu = 256 # 非导出可变变量 + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 +_name = "nginx" + +# 可导出变量 +cpu = _cpu +memory = _cpu * 2 +command = [_name] # 列表 +labels = { + run = "my-{}".format(_name) + env = "pre-prod" +} # a dict +image = "{}:1.14.2".format(_name) # 字符串格式 +service = "my-service" +``` + +而测试代码定义在 `my_config_test.k` 中,我们可以在其中导入 `my_config.k`: + +```python +import my_config + +# debugging +print(my_config.labels) # 通过打印调试 + +# test +assert len(my_config.labels) > 0, "labels can't be empty" # 使用 len() 得到列表长度 +assert "env" in my_config.labels, "env label is a must" +assert my_config.cpu >= 256, "cpu cannot be less than256" +``` + +## 9. 配置输入参数 + +有时我们需要获得通过从最终用户或平台动态获取的外部输入参数。 + +在这种情况下,我们可以按需传递 `priority` 和 `env` 参数: + +- 通过参数传递: `-D priority=1 -D env=pre-prod` +- 可以在 KCL 代码中使用 `option` 关键字获取这些值 + +```python +_priority = option("priority") # 非导出可变变量 +_env = option("env") # 非导出可变变量 +_cpu = 256 # 非导出可变变量 + +if _priority == 1: + _cpu = 256 +elif _priority == 2: + _cpu = 512 +elif _priority == 3: + _cpu = 1024 +else: + _cpu = 2048 + +_name = "nginx" +# 可导出变量 +cpu = _cpu +memory = _cpu * 2 +command = [_name] # 列表 +labels = { + run = "my-{}".format(_name) + env = _env +} # a dict +image = "{}:1.14.2".format(_name) # 字符串格式 +service = "my-service" +``` + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +```bash +kcl my_config.k -D priority=2 -D env=pre-prod +``` + +标准输出: + +```yaml +cpu: 512 +memory: 1024 +command: + - nginx +labels: + run: my-nginx + env: pre-prod +image: nginx:1.14.2 +service: my-service +``` + +## 10. 使用 Dict 简化逻辑表达式 + +当我们需要编写复杂的逻辑时,可以使用dict来简化逻辑的编写。 + +```python +_priority = option("priority") # 非导出可变变量 +_env = option("env") # 非导出可变变量 +_priorityCpuMap = { + "1" = 256 + "2" = 512 + "3" = 1024 +} +# 使用字典简化逻辑,默认值为2048 +_cpu = _priorityCpuMap[_priority] or 2048 +_name = "nginx" +# 可导出变量 +cpu = _cpu +memory = _cpu * 2 +command = [_name] # 列表 +labels = { + run = "my-{}".format(_name) + env = _env +} # a dict +image = "{}:1.14.2".format(_name) # 字符串格式 +service = "my-service" +``` + +使用 KCL 运行上述代码,将会看到以 yaml 格式生成的如下数据: + +KCL 命令: + +```bash +kcl my_config.k -D priority=2 -D env=pre-prod +``` + +标准输出: + +```yaml +cpu: 512 +memory: 1024 +command: + - nginx +labels: + run: my-nginx + env: pre-prod +image: nginx:1.14.2 +service: my-service +``` + +## 11. 最后 + +恭喜! + +我们已经完成了关于 KCL 的第一课程,我们使用 KCL 来替换我们的键值文本文件,以获得更好的编程支持。 + +建议立即查看架构代码实验,以了解如何使用 KCL `schema` 机制协作编写高级配置。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/_category_.json new file mode 100644 index 000000000..4f285ced9 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "错误与警告", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/exception.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/exception.md new file mode 100644 index 000000000..265c56b7e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/exception.md @@ -0,0 +1,1509 @@ +--- +title: "KCL 错误与警告" +linkTitle: "KCL 错误与警告" +type: "docs" +weight: 2 +description: KCL 错误与警告 +--- + +# KCL 错误与警告 + +文档的此部分中的文章介绍了由 KCL 生成的诊断错误和警告消息。 + +**注意:** +**KCL 可以报告多种错误和警告。找到错误或警告后,KCL 可能会对代码意向作出假设并尝试继续,以便可以同时报告更多问题。 如果工具做出错误假设,则后续错误或警告可能不适应与当前 KCL 程序。 因此,纠正项目中的问题时,请先纠正第一个错误或警告,然后重新运行获取新的错误信息。 一个修补程序可能会导致后续错误消失。** + +此部分文档的主要内容包括: + +[KCL 语法错误 (E1xxx)](#11-kcl-%E8%AF%AD%E6%B3%95%E9%94%99%E8%AF%AF-e1xxx) : 如果 KCL 在当前 KCL 程序中发现了非法的 KCL 语法,KCL 就会停止运行并输出 KCL 程序语法错误的提示信息. + +[KCL 编译错误 (E2xxx)](#12-kcl-%E7%BC%96%E8%AF%91%E9%94%99%E8%AF%AF-e2xxx) : 如果 KCL 在一个不包含语法错误的 KCL 程序中发现了与 KCL 语义不符的代码,KCL 就会停止运行并输出编译错误的提示信息。 + +[KCL 运行时错误 (E3xxx)](#13-kcl-%E8%BF%90%E8%A1%8C%E6%97%B6%E9%94%99%E8%AF%AF-e3xxx) : KCL 程序通过编译后会生成 KCL 字节码,如果 KCL 在执行 KCL 字节码过程中出现错误,KCL 就会停止运行并输出运行时错误的提示信息. + +[KCL 编译警告 (W2xxx)](#14-kcl-%E7%BC%96%E8%AF%91%E8%AD%A6%E5%91%8A-w2xxx) : 当 KCL 发现可能导致运行失败的 KCL 代码,KCL 不会立即停止运行,但是会输出潜在错误的警告提示。 + +## 1.1 KCL 语法错误 (E1xxx) + +KCL 会出现的语法错误信息如下表所示: + +| ewcode | KCL exception | messages | +| ------ | --------------------------------------------------------- | ----------------------- | +| E1001 | [InvalidSyntaxError](#invalidsyntaxerror) | Invalid syntax | +| E1002 | [KCLTabError](#taberror) | Tab Error | +| E1003 | [KCLIndentationError](#indentationerror) | Indentation Error | +| E1I37 | [IllegalArgumentSyntaxError](#illegalargumentsyntaxerror) | Illegal argument syntax | + +### InvalidSyntaxError + +如果在运行 KCL 时遇到错误: + +- `InvalidSyntaxError`, 对应的 encode 为 `E1001` + +那么此时 KCL 程序中出现了 + +- 非法的 KCL 语法。 + +可能出现错误的 KCL 程序片段如下: + +```python +a, b = 1, 2 # 通过 “=” 赋值多个变量在KCL中是非法的。 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: InvalidSyntax + --> /syntax_error/general/multiple_assign/case0/main.k:1:2 + | +1 | a, b = 1, 2 # Multiple assign is illegal in KCL syntax + | ^ expected statement + | +``` + +### TabError + +如果在运行 KCL 时遇到错误: `TabError` + +那么此时 KCL 程序中出现了 + +- Tab 与空格混用的问题。KCL 中禁止在代码缩进中混用 Tab 和空格。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + name: str # 通过tab表示缩进 + age: int # 通过四个空格标识缩进, + # 在当前运行环境中的四个空格与tab不同 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: InvalidSyntax + --> File /syntax_error/tab/tab_error_0/main.k:6:5 + | +3 | age: int = 1 + | ^ inconsistent use of tabs and spaces in indentation + | +``` + +可以尝试以下步骤来修复这个错误: + +- 在 KCL 程序中全部使用 Tab 或者全部使用四个空格,不要混用。 + +### IndentationError + +如果在运行 KCL 时遇到错误: `IndentationError` + +那么此时 KCL 程序中出现了 + +- 程序缩进错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + name: str # 使用一个tab或者四个空格表示缩进 + age: int # KCL不支持使用三个空格表示缩进 + info: str # KCL不支持使用两个空格表示缩进 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: InvalidSyntax + --> /syntax_error/indent/indent_error_0/main.k:3:4 + | +3 | age: int # three white spaces are illegal + | ^ unindent 3 does not match any outer indentation level + | +``` + +可以尝试以下步骤来修复这个错误: + +- 在 KCL 程序中全部使用 Tab 或者全部使用四个空格来表示缩进。 + +### IllegalArgumentSyntaxError + +如果在运行 KCL 时遇到错误: `IllegalArgumentSyntaxError` + +那么此时 KCL 程序中出现了 + +- 参数语法错误 + +可能出现错误的 KCL 程序片段如下: + +```python +# KCL中带有keyword的参数必须出现在不带有keyword参数后面 +# 带有keyword的参数: type="list", default={"key": "value"} +# 不带有keyword的参数: "key1" +a = option(type="list", default={"key": "value"}, "key1") +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: InvalidSyntax + --> /option/type_convert_fail_2/main.k:3:57 + | +3 | a = option(type="list", default={"key": "value"}, "key1") + | ^ positional argument follows keyword argument + | +``` + +可以尝试以下步骤来修复这个错误: + +- KCL 中带有 keyword 的参数必须出现在不带有 keyword 参数后面, 参数正常顺序: + +```python +func(input_1, ..., input_n, param_with_key_1 = input_with_key_1, ..., param_with_key_n = input_with_key_n) +``` + +## 1.2 KCL 编译错误 (E2xxx) + +KCL 会出现的编译错误信息如下表所示: + +| ewcode | KCL exception | messages | +| ------ | ----------------------------------------------------- | --------------------------------------------------- | +| E2F04 | [CannotFindModule](#cannotfindmodule-e2f04) | Cannot find the module | +| E2H13 | [UnKnownDecoratorError](#unknowndecoratorerror-e2h13) | UnKnown decorator | +| E2C15 | [MixinNamingError](#mixinnamingerror-e2c15) | Illegal mixin naming | +| E2C16 | [MixinStructureIllegal](#mixinstructureillegal-e2c16) | Illegal mixin structure | +| E2B17 | [CannotAddMembersError](#cannotaddmemberserror-e2b17) | Cannot add members to a schema | +| E2B20 | [IndexSignatureError](#indexsignatureerror-e2b20) | Invalid index signature | +| E2G22 | [TypeError](#typeerror-e2g22) | The type got is inconsistent with the type expected | +| E2L23 | [CompileError](#compileerror-e2l23) | An error occurs during compiling | +| E2L25 | [NameError](#nameerror-e2l25) | Name Error | +| E2L26 | [ValueError](#valueerror-e2l26) | Value Error | +| E2L27 | [KeyError](#keyerror-e2l27) | Key Error | +| E2L28 | [UniqueKeyError](#uniquekeyerror-e2l28) | Unique key error | +| E2A29 | [AttributeError](#attributeerror-e2a29) | Attribute error occurs during compiling | +| E2D32 | [MultiInheritError](#multiinheriterror-e2d32) | Multiple inheritance is illegal | +| E2D34 | [IllegalInheritError](#illegalargumenterror-e2i36) | Illegal inheritance | +| E2I36 | [IllegalArgumentError](#illegalargumenterror-e2i36) | Illegal argument during compiling | +| E3L41 | [ImmutableError](#immutableerror-e3l41) | Immutable variable is modified | + +### CannotFindModule (E2F04) + +如果在运行 KCL 时遇到错误: + +- `CannotFindModule`, 对应的 encode 为 `E2F04` + +那么此时 KCL 程序中出现了 + +- 无法找到导入模块错误 + +可能出现错误的 KCL 程序片段如下: + +```python +import .some0.pkg1 as some00 # some0 not found in package + +Name1 = some00.Name # some0.pkg1.name +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2F04]: CannotFindModule + --> import_abs_fail_0/app-main/main.k:1:1 + | +1 | import .some0.pkg1 as some00 # some0 not found in package + | Cannot find the module .some0.pkg1 + | +``` + +可以尝试以下步骤来修复这个错误: + +- 在 import 路径下添加导入模块文件。 + +### UnKnownDecoratorError (E2H13) + +如果在运行 KCL 时遇到错误: + +- `UnKnownDecoratorError`, 对应的 encode 为 `E2H13` + +那么此时 KCL 程序中出现了 + +- 未知的装饰器错误 + +可能出现错误的 KCL 程序片段如下: + +```python +@err_deprecated # 这是一个非法的装饰器 +schema Person: + firstName: str = "John" + lastName: str + name: str + +JohnDoe = Person { + name: "deprecated" +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> deprecated/unknown_fail_1/main.k:1:2 + | +1 | @err_deprecated # 这是一个非法的装饰器 + | ^ UnKnown decorator err_deprecated + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查装饰器是否存在。 + +### MixinNamingError (E2C15) + +如果在运行 KCL 时遇到错误: + +- `MixinNamingError`, 对应的 encode 为 `E2C15` + +那么此时 KCL 程序中出现了 + +- Mixin 命名错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + firstName: str + lastName: str + fullName: str + +schema Fullname: # Mixin的名称应该以Mixin结尾 + fullName = "{} {}".format(firstName, lastName) + +schema Scholar(Person): + mixin [Fullname] + school: str + +JohnDoe = Scholar { + "firstName": "John", + "lastName": "Doe", + "fullName": "Doe Jon" +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2D34]: IllegalInheritError + --> mixin/invalid_name_failure/main.k:10:12 + | +10 | mixin [Fullname] + | ^ illegal schema mixin object type 'Fullname' + | +``` + +可以尝试以下步骤来修复这个错误: + +- 如果 schema 是一个 mixin,那么这个 schema 的名称应该以 Mixin 结尾。 + +### MixinStructureIllegal (E2C16) + +如果在运行 KCL 时遇到错误: + +- `MixinStructureIllegal`, 对应的 encode 为 `E2C16` + +那么此时 KCL 程序中出现了 + +- Mixin 结构错误。 + +可以尝试以下步骤来修复这个错误: + +- 检查作为 Mixin 的 Schema 的结构。 + +### CannotAddMembersError (E2B17) + +如果在运行 KCL 时遇到错误: + +- `CannotAddMembersError`, 对应的 encode 为 `E2B17` + +那么此时 KCL 程序中出现了 + +- 使用 Schema 中不存在的成员。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Girl: + gender: str = "female" + +alice = Girl { + "first": "alice", # Schema中没有成员“first” + "last": " Green", # Schema中没有成员“last” + "age": 10 # Schema中没有成员“age” +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> /invalid/add_attribute/main.k:5:5 + | +5 | "first": "alice", + | ^ Cannot add member 'first' to schema 'Girl' + | + +error[E2L23]: CompileError + --> /invalid/add_attribute/main.k:6:5 + | +6 | "last": " Green", + | ^ Cannot add member 'last' to schema 'Girl' + | + +error[E2L23]: CompileError + --> /invalid/add_attribute/main.k:7:5 + | +7 | "age": 10 + | ^ Cannot add member 'age' to schema 'Girl' + | +``` + +可以尝试以下步骤来修复这个错误: + +- 为 Schema 添加缺少的成员。 +- 不要使用 Schema 中不存在的成员。 + +### IndexSignatureError [E2B20] + +如果在运行 KCL 时遇到错误: + +- `IndexSignatureError`, 对应的 encode 为 `E2B20` + +那么此时 KCL 程序中出现了 + +1. 在一个 schema 中使用多个索引签名。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Data: + [str]: str + [str]: int # 在同一个schema中使用了多个索引签名 + +data = Data { + name: "test" +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError +---> index_signature/fail_1/main.k:3:5 + | +3 | [str]: int + | 5 ^ only one index signature is allowed in the schema + | +``` + +可以尝试以下步骤来修复这个错误: + +- 删除多余的索引签名。 + +2. schema 中索引签名的名称与 schema 中其他属性的名称存在同名冲突。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Data: + name: str # name + [name: str]: str # 已有名称为name的schema属性 + +data = Data { + name: "test" +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: IndexSignatureError + --> index_signature/fail_2/main.k:3:5 + | +3 | [name: str]: str # the same name with the above attribute + | ^ index signature attribute name 'name' cannot have the same name as schema attributes + | +``` + +可以尝试以下步骤来修复这个错误: + +- 删除 schema 中出现同名冲突的属性或者索引签名,或者为它们更换不同的名称。 + +3. schema 索引签名的类型与 schema 实例化的属性类型冲突。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Data: + [str]: int + +data = Data { + name: "test" # 索引签名为 [str]:int, "test"的类型不是int. +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2G22]: TypeError + --> index_signature/fail_3/main.k:5:5 + | +5 | name: "test" # Conflict with [str]:int, "test" is a string. + | ^ expected int, got str(test) + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查 schema 索引签名的类型与 schema 实例中的属性类型是否一致。 + +4. Schema 中的属性与索引签名冲突 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Data: + count: int # int 和 str 冲突 + [str]: str + +data = Data { + count: 1 +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: IndexSignatureError + --> index_signature/fail_4/main.k:2:5 + | +2 | count: int + | ^ the type 'int' of schema attribute 'count' does not meet the index signature definition [str]: str + | +``` + +可以尝试以下步骤来修复这个错误: + +- 调整 Schema 属性或者调整索引签名。 + +### TypeError (E2G22) + +如果在运行 KCL 时遇到错误: + +- `TypeError`, 对应的 encode 为 `E2G22` + +那么此时 KCL 程序中出现了 + +- 静态类型检查错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + firstName: str + lastName: int + +JohnDoe = Person { + "firstName": "John", + "lastName": "Doe" # Schema中定义lastName: int +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2G22]: TypeError + --> type/type_fail_0/main.k:7:5 + | +7 | "lastName": "Doe" # Type Error,lastName: int,“Doe” is a string. + | ^ expected int, got str(Doe) + | + + --> type/type_fail_0/main.k:3:5 + | +3 | lastName: int + | ^ variable is defined here, its type is int, but got str(Doe) + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查赋给某个变量的值的类型与这个变量的类型是否一致。 + +### CompileError (E2L23) + +如果在运行 KCL 时遇到错误: + +- `CompileError`, 对应的 encode 为 `E2L23` + +那么此时 KCL 程序中出现了 + +1. 不支持的类型合并 + +可能出现错误的 KCL 程序片段如下: + +```python +_data = [1, 2, 3] +_data |= "value" +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2G22]: TypeError + --> union/fail/fail_1/main.k:2:1 + | +2 | _data |= "value" + | ^ unsupported operand type(s) for |: '[int]' and 'str(value)' + | +``` + +1. 不支持的操作符类型 + +可能出现错误的 KCL 程序片段如下: + +```python +a = None +b = 1 + None # KCL中不支持None和int之间进行+操作 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2G22]: TypeError + --> operator/operator_fail_0/main.k:2:5 + | +2 | b = 1 + None # Unsupported operand type + for int and None + | ^ unsupported operand type(s) for +: 'int(1)' and 'NoneType' + | +``` + +可以尝试以下步骤来修复这个错误: + +- 调整操作符号,使其同时支持两个操作数的类型。 +- 调整操作数,使其同时符合操作符号的约束。 + +1. 没有定义的变量 + +可能出现错误的 KCL 程序片段如下: + +```python +a = 1 +b = "${c + 1}" # 'c' 没有定义 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> var_not_define_fail_0/main.k:2:8 + | +2 | b = "${c + 1}" # 'c' is not defined + | ^ name 'c' is not defined + | +``` + +可以尝试以下步骤来修复这个错误: + +- 对未定义的变量进行定义。 +- 在表达式中去掉对未定义变量的操作。 + +4. 无效的赋值表达式 + +可能出现错误的 KCL 程序片段如下: + +```python +# pkg.k +a = 1 + +# main.k +import pkg +pkg.a |= 2 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2G22]: TypeError + --> pkg_inplace_modify_1/main.k:3:1 + | +6 | pkg |= 2 + | ^ unsupported operand type(s) for |: 'module 'pkg'' and 'int(2)' + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查赋值表达式的内容。 + +1. 无效的字符串表达式 + +可能出现错误的 KCL 程序片段如下: + +```python +a = 1 +b = "${b = a + 1}" # Invalid string interpolation expression +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> invalid_format_value_fail_0/main.k:2:5 + | +2 | b = "${b = a + 1}" + | 5 ^ invalid string interpolation expression 'b = a + 1' + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查字符串表达式的内容。 + +1. 无效的循环变量 + +可能出现错误的 KCL 程序片段如下: + +```python +data = {"key1": "value1", "key2": "value2"} +dataLoop = [i for i, j, k in data] # the number of loop variables can only be 1 or 2 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> dict/invalid_loop_var_fail_0/main.k:2:25 + | +2 | dataLoop = [i for i, j, k in data] # the number of loop variables can only be 1 or 2 + | ^ the number of loop variables is 3, which can only be 1 or 2 + | +``` + +### NameError (E2L25) + +如果在运行 KCL 时遇到错误: + +- `NameError`, 对应的 encode 为 `E2L25` + +那么此时 KCL 程序中出现了 + +- 试图访问的变量名不存在 + +可以尝试以下步骤来修复这个错误: + +- 检查报错信息中出现的变量是否存在。 + +### ValueError (E2L26) + +如果在运行 KCL 时遇到错误: + +- `ValueError`, 对应的 encode 为 `E2L26` + +那么此时 KCL 程序中出现了 + +- 值错误,传给参数的类型不正确 + +可以尝试以下步骤来修复这个错误: + +- 检查参数的具体类型。 + +### KeyError (E2L27) + +如果在运行 KCL 时遇到错误: + +- `KeyError`, 对应的 encode 为 `E2L27` + +那么此时 KCL 程序中出现了 + +- 使用了 dict 中不存在的 key 时引发的 key 错误 + +可以尝试以下步骤来修复这个错误: + +- 检查字典中是否存在 key。 + +### UniqueKeyError (E2L28) + +如果在运行 KCL 时遇到错误: + +- `UniqueKeyError`, 对应的 encode 为 `E2L28` + +那么此时 KCL 程序中出现了 + +- 变量同名或重复定义。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + name: str = "kcl" + age: int = 1 + +schema Person: + aa: int + +x0 = Person{} +x1 = Person{age:101} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L28]: UniqueKeyError + --> /schema/same_name/main.k:5:8 + | +5 | schema Person: + | ^ Unique key error name 'Person' + | + + --> /schema/same_name/main.k:1:8 + | +1 | schema Person: + | ^ The variable 'Person' is declared here + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查出现错误的名称是否已经被使用。 + +### AttributeError (E2A29) + +如果在运行 KCL 时遇到错误: + +- `AttributeError`, 对应的 encode 为 `E2A29` + +那么此时 KCL 程序中出现了 + +- Schema 的属性错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +# pkg +schema A: + field_A: str + +# main +import pkg as p + +a = p.D + 1 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2G22]: TypeError + --> /import/module/no_module_attr_fail_0/main.k:4:5 + | +4 | a = p.D + 1 + | ^ module 'pkg' has no attribute D + | +``` + +可以尝试以下步骤来修复这个错误: + +- 在使用 Schema 属性时检查这个属性是否存在。 + +### MultiInheritError (E2D32) + +如果在运行 KCL 时遇到错误: + +- `MultiInheritError`, 对应的 encode 为 `E2D32` + +那么此时 KCL 程序中出现了 + +- 多继承错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + firstName: str + lastName: str + +schema KnowledgeMixin: + firstName: int + subject: str + +schema Scholar(KnowledgeMixin, Person): # KCL中不支持多继承 + school: str +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: InvalidSyntax + --> /schema/inherit/multi_inherit_fail_1/main.k:9:30 + | +9 | schema Scholar(KnowledgeMixin, Person): + | ^ expected one of [")"] got , + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查程序的继承结构,KCL 中不支持多继承。 + +### IllegalInheritError (E2D34) + +如果在运行 KCL 时遇到错误: + +- `IllegalInheritError`, 对应的 encode 为 `E2D34` + +那么此时 KCL 程序中出现了 + +- 不合法的继承结构 + +可能出现错误的 KCL 程序片段如下: + +```python +schema FullnameMixin: + fullName = "{} {}".format(firstName, lastName) + +schema Scholar(FullnameMixin): # KCL中不支持Schema继承Mixin + school: str +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError +Invalid value for top level arguments +``` + +可以尝试以下步骤来修复这个错误: + +- KCL 中 Schema 支持单继承 Schema。 + +### IllegalArgumentError (E2I36) + +如果在运行 KCL 时遇到错误: + +- `IllegalArgumentError`, 对应的 encode 为 `E2I36` + +那么此时 KCL 程序中出现了 + +- 参数错误 + +可能出现错误的 KCL 程序片段如下: + +```python +a = option("key") + +# kcl main.k -D key=value= +# key=value= is an illegal expression +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError +Invalid value for top level arguments +``` + +可以尝试以下步骤来修复这个错误: + +- 检查通过命令设置的 KCL option 参数是否为合法参数。 + +### ImmutableError (E3L41) + +如果在运行 KCL 时遇到错误: + +- `ImmutableError`, 对应的 encode 为 `E3L41` + +那么此时 KCL 程序中出现了 + +- 不可变量的值发生改变 + +可能出现错误的 KCL 程序片段如下: + +```python +a = 2147483646 +a += 1 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E1001]: ImmutableError + --> augment_assign/main.k:2:1 + | +2 | a += 1 + | ^ Immutable variable 'a' is modified during compiling + | + + --> augment_assign/main.k:1:1 + | +1 | a = 2147483646 + | ^ The variable 'a' is declared here firstly + | +note: change the variable name to '_a' to make it mutable +``` + +可以尝试以下步骤来修复这个错误: + +- 将被改变的不可变量设置为私有或者去掉对不可变量值的改动。 + +## 1.3 KCL 运行时错误 (E3xxx) + +KCL 会出现的运行时错误信息如下表所示: + +| ewcode | KCL exception | messages | +| ------ | ------------------------------------------------------------------- | --------------------------------------------------- | +| E3F06 | [RecursiveLoad](#recursiveload-e3f06) | Recursively loading module | +| E3K04 | [FloatOverflow](#floatoverflow-e3k04) | Float overflow | +| E3K09 | [IntOverflow](#intoverflow-e3k09) | Integer overflow | +| E3N11 | [DeprecatedError](#deprecatederror-e3n11) | Deprecated error | +| E3A30 | [AttributeRuntimeError](#attributeruntimeerror-e3a30) | Attribute error occurs at runtime | +| E3G21 | [TypeRuntimeError](#typeruntimeerror-e3g21) | The type got is inconsistent with the type expected | +| E3B17 | [SchemaCheckFailure](#schemacheckfailure-e3b17) | Schema check is failed to check condition | +| E3B19 | [CannotAddMembersRuntimeError](#cannotaddmembersruntimeerror-e3b19) | Cannot add members to a schema | +| E3M38 | [EvaluationError](#evaluationerror-e3m38) | Evaluation failure | +| E3M39 | [InvalidFormatSpec](#invalidformatspec-e3m39) | Invalid format specification | +| E3M40 | [AssertionError](#assertionerror-e3m40) | Assertion failure | +| E3M42 | [RecursionError](#recursionerror-e3m42) | Recursively reference | + +### RecursiveLoad (E3F06) + +如果在运行 KCL 时遇到错误: + +- `RecursiveLoad`, 对应的 encode 为 `E3F06` + +那么此时 KCL 程序中出现了 + +- 循环导入错误 + +可能出现错误的 KCL 程序片段如下: + +``` +# module.k +import main # module.k 导入了 main.k + +print('module') + +# main.k +import module # main.k 导入了 module.k + +print('main') +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> /import/recursive_import_fail/main.k:4 + | +2 | import module # main.k imports module.k + | ^ There is a circular import reference between module main and module + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查包的导入部分是否存在循环导入的问题。 + +### FloatOverflow (E3K04) + +如果在运行 KCL 时遇到错误: + +- `FloatOverflow`, 对应的 encode 为 `E3K04` + +那么此时 KCL 程序中出现了 + +- 浮点数溢出 + +可能出现错误的 KCL 程序片段如下: + +```python +uplimit = 3.402823466e+39 +epsilon = 2.220446049250313e-16 +a = uplimit * (1 + epsilon) + +# kcl main.k -r -d +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /range_check_float/overflow/number_0/main.k:3:1 + | +3 | a = uplimit * (1 + epsilon) + | 3.4028234660000003e+39: A 32-bit floating point number overflow + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查浮点数的值是否在 KCL 支持的数字范围内。 + +### IntOverflow (E3K09) + +如果在运行 KCL 时遇到错误: + +- `IntOverflow`, 对应的 encode 为 `E3K09` + +那么此时 KCL 程序中出现了 + +- 整数溢出 + +可能出现错误的 KCL 程序片段如下: + +```python +_a = 9223372036854775807 +_a += 1 + +# kcl test.k -d +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /range_check_int/augment_assign_fail_1/main.k:2:1 + | +2 | _a += 1 + | 9223372036854775808: A 64 bit integer overflow + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查整数的值是否在 KCL 支持的数字范围内。 + +### DeprecatedError (E3N11) + +如果在运行 KCL 时遇到错误: + +- `DeprecatedError`, 对应的 encode 为 `E3N11` + +那么此时 KCL 程序中出现了 + +- 使用废弃代码 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + firstName: str = "John" + lastName: str + @deprecated(version="1.16", reason="use firstName and lastName instead", strict=True) + name: str + +JohnDoe = Person { + name: "deprecated" # name已经过时,并且strict设置为True +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /range_check_float/overflow/number_0/main.k:7:1 + | +7 | JohnDoe = Person { + | name was deprecated since version 1.16, use firstName and lastName instead + | +``` + +可以尝试以下步骤来修复这个错误: + +- strict 设置为 True 时无法使用过时的代码,可以将 strict 设置为 False,将不会出现错误,而是输出一个警告。 +- 调整代码,不使用已经过时的代码。 + +### AttributeRuntimeError (E3A30) + +如果在运行 KCL 时遇到错误: + +- `AttributeRuntimeError`, 对应的 encode 为 `E3A30` + +那么此时 KCL 程序中出现了 + +- 属性错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +import math + +a = math.err_func(1) # err_func is not found in math +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /import/module/no_module_attr_fail_2/main.k:3:5 + | +3 | a = math.err_func(1) # err_func is not found in math + | ^ module 'math' has no attribute err_func + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查属性调用是否正确。 + +### TypeRuntimeError (E3G21) + +如果在运行 KCL 时遇到错误: + +- `TypeRuntimeError`, 对应的 encode 为 `E3G21` + +那么此时 KCL 程序中出现了 + +- 类型检查错误 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + name: str = "Alice" + +_personA = Person {} +_personA |= {"name" = 123.0} # name: str = "Alice" +personA = _personA +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /fail/fail_4/main.k:2:1 + | +2 | name: str = "Alice" + | expect str, got float + | +``` + +可以尝试以下步骤来修复这个错误: + +- 停止错误的类型合并或者将类型调整为 KCL 支持的类型合并。 + +### SchemaCheckFailure (E3B17) + +如果在运行 KCL 时遇到错误: + +- `SchemaCheckFailure`, 对应的 encode 为 `E3B17` + +那么此时 KCL 程序中出现了 + +- Schema 中的 check 条件冲突 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Person: + lastName: str + age: int + check: + age < 140, "age is too large" + +JohnDoe = Person { + "lastName": "Doe", + "age": 1000 # Schema中的check条件为: age < 140 +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /check_block/check_block_fail_1/main.k:7:11 + | +7 | JohnDoe = Person { + | ^ Instance check failed + | + + --> /check_block/check_block_fail_1/main.k:5:1 + | +5 | age < 140, "age is too large" + | Check failed on the condition + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查 Schema 的属性与 check 中的条件是否符合 + +### CannotAddMembersRuntimeError (E3B19) + +如果在运行 KCL 时遇到错误: + +- `CannotAddMembersRuntimeError`, 对应的 encode 为 `E3B19` + +那么此时 KCL 程序中出现了 + +- 访问 Schema 中不存在的成员 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Name: + name: str + +schema Person: + name: Name + +person = Person { + name.err_name: "Alice" # err_name is not found in schema Name +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> /nest_var/nest_var_fail_1/main.k:8:5 + | +8 | name.err_name: "Alice" # err_name is not found in schema Name + | ^ Cannot add member 'err_name' to schema 'Name' + | +``` + +可以尝试以下步骤来修复这个错误: + +- 为 Schema 添加不存在的成员。 +- 访问 Schema 中存在的成员。 + +### EvaluationError (E3M38) + +如果在运行 KCL 时遇到错误: + +- `EvaluationError`, 对应的 encode 为 `E3M38` + +那么此时 KCL 程序中出现了 + +- 当 KCL 中数值计算过程出现了错误。 + +可能出现错误的 KCL 程序片段如下: + +```python +_list1 = [1, 2, 3] # _list1 is a variable, and its type can only be known at runtime +_list2 = None # _list1 is a variable, and its type can only be known at runtime + +result2 = _list1 + _list2 # list + NoneType is illegal +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /datatype/list/add_None_fail/main.k:1 + | +4 | result2 = _list1 + _list2 # list + NoneType is illegal + | can only concatenate list (not "NoneType") to list + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查表达式中是否存在变量为 None,或者非法的计算过程。 + +###0 InvalidFormatSpec (E3M39) + +如果在运行 KCL 时遇到错误: + +- `InvalidFormatSpec`, 对应的 encode 为 `E3M39` + +那么此时 KCL 程序中出现了 + +- 非法的字符串格式 + +可能出现错误的 KCL 程序片段如下: + +```python +a = 1 +b = 1 +data = "${a: #js}" + " $$ " # KCL插值字符串中,#js是非法的 +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> /datatype/str_interpolation/invalid_format_spec_fail_0/main.k:3 + | +3 | data = "${a: #js}" + " $$ " # #js is illegal string + | ^ #js is a invalid format spec + | +``` + +可以尝试以下步骤来修复这个错误: + +- 将非法 String 调整为 KCL 标准支持的 String。 + +### AssertionError (E3M40) + +如果在运行 KCL 时遇到错误: + +- `AssertionError`, 对应的 encode 为 `E3M40` + +那么此时 KCL 程序中出现了 + +- Assert False + +可能出现错误的 KCL 程序片段如下: + +```python +assert False +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E3M38]: EvaluationError + --> /assert/invalid/fail_0/main.k:1 + | +1 | assert False + | + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查 Assert 的条件,Assert 条件为 False 时,就会出现此类错误,去掉 Assert 语句或改变条件为 True。 + +### CycleInheritError (E2D33) + +如果在运行 KCL 时遇到错误: + +- `CycleInheritError`, 对应的 encode 为 `E2D33` + +那么此时 KCL 程序中出现了 + +- 循环继承 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Parent(Son): + parent_field: str + +schema Son(GrandSon): + son_field: str + +schema GrandSon(Parent): + grandson_field: str + +parent = Parent { + parent_field: "" +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +error[E2L23]: CompileError + --> /inherit/cycle_inherit_fail_1/main.k:7:8 + | +7 | schema GrandSon(Parent): + | ^ There is a circular reference between schema GrandSon and Parent + | +``` + +可以尝试以下步骤来修复这个错误: + +- 检查 Schema 的继承关系,避免出现 A 继承 B,B 继承 A 的情况。 + +### RecursionError (E3M42) + +如果在运行 KCL 时遇到错误: + +- `RecursionError`, 对应的 encode 为 `E3M42` + +那么此时 KCL 程序中出现了 + +- 循环引用 + +可能出现错误的 KCL 程序片段如下: + +```python +schema Parent(Son): + parent_field: str + son: Son = Son { # Parent has attribute Son + parent: Parent { + parent_field: "123" + } + } + +schema Son: + son_field: str + parent: Parent = Parent { # Son has attribute Parent + son: Son { + son_field: "123" + } + } + +parent = Parent { + parent_field: "", +} +``` + +KCL 在运行上述 KCL 程序片段时的输出信息如下. + +```shell +thread 'main' has overflowed its stack +fatal runtime error: stack overflow +``` + +可以尝试以下步骤来修复这个错误: + +- 检查 Schema 中的属性成员,避免出现循环引用的问题。 + +## 1.4 KCL 编译警告 (W2xxx) + +KCL 中的编译警告如下表所示: + +| ewcode | KCL exception | messages | +| ------ | --------------------------------------------- | ------------------ | +| W2K04 | [FloatUnderflow](#floatunderflow-w2k04) | Float underflow | +| W2P10 | [InvalidDocstring](#invaliddocstring-w2p10) | Invalid docstring | +| W2N12 | [DeprecatedWarning](#deprecatedwarning-w2n12) | Deprecated warning | + +### FloatUnderflow (W2K08) + +如果在运行 KCL 时遇到错误: + +- `FloatUnderflow`, 对应的 encode 为 `W2K08` + +可以尝试以下步骤来修复这个错误: + +- 检查浮点数的值是否在 KCL 支持的数字范围内。 + +### InvalidDocstring (W2P10) + +如果在运行 KCL 时遇到错误: + +- `InvalidDocstring`, 对应的 encode 为 `W2P10` + +那么此时 KCL 程序中出现了 + +- 无效的 doc 内容 + +可以尝试以下步骤来修复这个错误: + +- 请按照 KCL 标准编写 doc。 + +### DeprecatedWarning (W2N12) + +如果在运行 KCL 时遇到错误: + +- `DeprecatedWarning`, 对应的 encode 为 `W2N12` + +那么此时 KCL 程序中出现了 + +- 过时的代码警告 + +可以尝试以下步骤来修复这个错误: + +- 尽量不要使用已经过时的代码。如果将 strict 设置为 True,KCL 将会输出错误,并停止运行。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/index.md new file mode 100644 index 000000000..e4f702ecc --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/error/index.md @@ -0,0 +1 @@ +# 错误与警告 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/index.md new file mode 100644 index 000000000..66fd3dde3 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/index.md @@ -0,0 +1 @@ +# KCL diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/_category_.json new file mode 100644 index 000000000..c088e386f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "规范", + "position": 3 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/codestyle.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/codestyle.md new file mode 100644 index 000000000..1a2f9c985 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/codestyle.md @@ -0,0 +1,624 @@ +--- +title: "Code Style" +linkTitle: "Code Style" +type: "docs" +weight: 2 +description: Code Style +--- + +## Introduction + +This document gives the KCL code style conventions. Good code style can play a vital role in the development and maintenance of the project. We can learn the KCL code style by referring to the full text of the description and sample codes, and use KCL format and lint tools to help coding. + +## Source File Encoding + +KCL file encoding should always use **UTF-8**. + +## Code Layout + +### Indentation + +Use **4 spaces** per indentation level such as in the schema statement and if statement. + +```python +schema PersonA: + name: str # non-recommended + age: int + +schema PersonB: + name: str # recommended + age: int + +if True: + a = 1 # recommended +elif True: + b = 2 # non-recommended +else: + c = 3 # non-recommended +``` + +The closing brace/bracket/parenthesis on multiline constructs should line up under **first character** of the line that starts the multiline construct, as in: + +```python +# valid and recommended +my_list = [ + 1, 2, 3, + 4, 5, 6, +] +``` + +```python +# invalid +my_list = [ + 1, 2, 3, + 4, 5, 6, + ] +``` + +### Tabs or Spaces + +- Spaces are the preferred indentation method. +- Tabs should be used solely to remain consistent with code that is already indented with tabs. + +KCL disallows mixing the use of tabs and spaces for indentation and an error will be reported during the compile time. + +### Blank Lines + +- Surround top-level schema definitions with one blank line. +- Keep at most one blank line between two statements and remove redundant blank lines. +- Remove extra blank characters at the end of the line +- Remove extra blank characters in a blank line. +- There is no blank line in the header of the file, start writing from the first line. +- Only one blank line will be left at the end of the KCL file. + +```python +# Remove blank lines in the file header +a = 1 # Remove white space at the end of the line +# Keep at most one blank line between two statements + +b = 2 +# Only leave one blank line at the end of the file + +``` + +### Inline Expressions + +Write indentation of KCL `if`, `elif`, `else` and other conditions on different lines. + +```python +if True: print("") # non-recommended + +if True: # recommended + print("") +``` + +### Line Break and Continuation lines + +- For long expressions, use the line continuation symbol `\` and keep the left end of multiple expressions aligned. +- The 4-space rule is optional for continuation lines. + +```python +anotherString = "Too long expression " + \ + "Too long expression " # non-recommended + +longString = "Too long expression " + \ + "Too long expression " + \ + "Too long expression " # recommended +``` + +### When to Use Trailing Commas + +- Always use trailing commas. + +### Maximum Line Length + +- The general recommendation is **80 characters** but not absolute. + +### Symbol Break White Space + +Try to keep the spaces between different symbols, but not too many, usually one is good. + +```python +a = 1 # recommended +b = 1 + 2 # non-recommended +``` + +### Whitespace in Expressions and Statements + +Avoid extraneous whitespace in the following situations: + +- The parentheses `()`, brackets `[]` and braces `{}` in the expression have no spaces inside. + +```python +a = (1 + 2) # recommended +b = ( 1 + 2 ) # non-recommended + +c = [1, 2, 3] # recommended +d = [ 1, 2, 3 ] # non-recommended + +e = {key = "value"} # recommended +f = { key = "value" } # non-recommended +``` + +```python +spam(ham[1], {eggs = 2}) # recommended +spam( ham[ 1 ], { eggs = 2 } ) # non-recommended +``` + +- Between a trailing comma and a following close parenthesis. + +```python +foo = [0,] # recommended +bar = [0, ] # non-recommended +``` + +- Immediately before the open parenthesis that starts the argument list of a function call. + +```python +print(1) # recommended +print (1) # non-recommended +``` + +- Immediately before the open parenthesis that starts indexing or slicing. + +```python +dct = {key = "value"} +lst = [1, 2, 3] + +a = dct['key'] # recommended +b = dct ['key'] # non-recommended + +c = lst[0] # recommended +d = lst [1] # non-recommended +``` + +- More than one space around an assignment `=` (or other) operator to align it with another. + +```python +# recommended: +x = 1 +y = 2 +long_variable = 3 +``` + +```python +# non-recommended: +x = 1 +y = 2 +long_variable = 3 +``` + +- Always surround these binary operators with a single space on either side: assignment (`=`), augmented assignment (`+=`, `-=`, etc.), comparisons (`==`, `<`, `>`, `!=`, `<=`, `>=`, `in`, `not in`, `is`, `is not`), booleans (`and`, `or`, `not`). + +```python +# recommended: +i = i + 1 +submitted += 1 +x = x * 2 - 1 +hypot2 = x * x + y * y +c = (a + b) * (a - b) +``` + +```python +# non-recommended: +i = i+1 +submitted+=1 +x = x*2 - 1 +hypot2 = x*x + y*y +c = (a+b) * (a-b) +``` + +- Break one blank line between different statements e.g., import, schema and expression statements. + +```python +import math +import net + +schema Person: + name: str + +person = Person { + name = "Alice" +} +``` + +- Compound statements (multiple statements on the same line) are generally discouraged + +```python +# recommended: +if foo == 'blah': + do_blah_thing() +do_one() +do_two() +do_three() +``` + +```python +# non-recommended: +if foo == 'blah': do_blah_thing() +do_one(); do_two(); do_three() +``` + +## Naming Conventions + +### Naming Styles + +The following naming styles are commonly distinguished: + +- `b` (single lowercase letter) +- `B` (single uppercase letter) +- `lowercase` +- `lower_case_with_underscores` +- `UPPERCASE` +- `UPPER_CASE_WITH_UNDERSCORES` +- `CapitalizedWords` (capitalize all letters of the acronym in `CapitalizedWords` e.g., `HTTPServer`.) +- `mixedCase` (differs from `CapitalizedWords` by initial lowercase character) +- `Capitalized_Words_With_Underscores` (ugly and non-recommended) + +### Names to Avoid + +Never use the characters 'l' (lowercase letter el), 'O' (uppercase letter oh), or 'I' (uppercase letter eye) as single-character variable names. + +### Package and Module Names + +Package and module names should have short, all-lowercase names. + +### Schema Names + +Schema names should normally use the `CapWords` convention. + +### Constants + +Constants are usually defined on a module level and written in all capital letters with underscores separating words such as `MAX_OVERFLOW` and `TOTAL`. + +## Import + +- Imports should usually be on separate lines. +- Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants. +- Imports should be grouped in the following order and we should put a blank line between each group of imports. + 1. Standard library imports. + 2. Related third party plugin imports. + 3. Local application/library specific imports. +- Use an alias when we import a package name with a relatively long path. +- Leave only one space between the Import keyword and the package name. + +```python +import net # recommended +import math # non-recommended + +import ..pkg.internal_pkg as alias_pkg # recommended +``` + +## Comments + +- Comments should be complete sentences. The first word should be capitalized unless it is an identifier that begins with a lower-case letter (never alter the case of identifiers!). +- Block comments generally consist of one or more paragraphs built out of complete sentences, with each sentence ending in a period. +- Use two spaces after a sentence-ending period in multi-sentence comments, except after the final sentence. + +### Block Comments + +Block comments generally apply to some (or all) code that follows them, and are indented to the same level as that code. Each line of a block comment starts with a `#` and **a single space**(unless it is indented text inside the comment). + +Paragraphs inside a block comment are separated by a line containing a single `#`. + +```python +# This is a block comment +a = 1 +``` + +### Inline Comments + +Use inline comments sparingly. + +An inline comment is a comment on the same line as a statement. Inline comments should be separated by **at least two spaces** from the statement. They should start with a `#` and **a single space**. + +```python +a = 1 # This is an inline comment +``` + +### Documentation Strings + +Write doc strings for all public schema and schema attributes. + +```python +schema Person: + """ + Person schema doc string + """ + + name: str = "Alice" +``` + +## String + +- Single-quoted strings and double-quoted strings are the same in KCL. +- Use double-quoted string with lowercase prefix +- For triple-quoted strings, always use double quote characters to be consistent with the docstring convention. +- When a string contains single or double quote characters, use the other one to avoid backslashes in the string. + +```python +strC = "'123'" # recommended +strD = "\"123\"" # non-recommended +``` + +## Number + +- Use lowercase for the prefix of non-decimal numbers, and use uppercase for the number itself. + +```python +foo = 0xAB # recommended +bar = 0Xab # non-recommended +``` + +## Operators + +### Binary Operators + +- Leave only one space before and after the assignment `=`. +- Leave only one space before and after the binary operator in the expression. + +```python +a = 1 # recommended +b=2 # non-recommended +c= 3 # non-recommended +d =4 # non-recommended + +_value = (1 + 2 * 3) # recommended +_value = (1+2*3) # non-recommended +``` + +### Unary Operators + +- There is only no space after unary operators e.g., `~`, `+` and `-`. + +```python +_value = 1 + -2 * ~3 # recommended +_value = 1+ - 2 * ~ 3 # non-recommended +``` + +- There is no space after `**` and `*` in the dict/list deduction expressions and argument expressions. + +```python +_list = [1, 2, 3] +_list = [*_list, [4, 5 ,6]] # recommended +_list = [* _list, [4, 5 ,6]] # non-recommended + +_dict = {**{k = "v"}, **{k = "v"}} # recommended +_dict = {** {k = "v"}, ** {k = "v"}} # non-recommended +``` + +- Use `is not` operator rather than `not ... is`. + +```python +# recommended: +if foo is not None: + a = 1 +``` + +```python +# non-recommended: +if not foo is None: + a = 1 +``` + +## Dict + +- There is no space before the colon `:` at the instantiation of KCL dict and schema config, and a space after the colon `:`. + +```python +d1 = {labels: {k1 = "v1"}} # recommended +d2 = {labels : {k1 = "v1"}} # non-recommended +d3 = {labels :{k1 = "v1"}} # non-recommended +``` + +- Always surround the override attribute operator `=` and the insert attribute operator `+=` with a single space on either sid. + +```python +d1 = {key = "value"} # recommended +d2 = {key= "value"} # non-recommended +d3 = {key ="value"} # non-recommended +``` + +```python +d1 = {key += [0, 1, 2]} # recommended +d2 = {key+= [0, 1, 2]} # non-recommended +d3 = {key +=[0, 1, 2]} # non-recommended +``` + +- Remove all commas at the end of the line in the KCL multiline dict because the end commas of each line are optional. + +```python +d = { + key1 = "value1" + key2 = "value2" + key3 = "value3" + key4 = "value4" +} +``` + +## List + +- Keep only **one space** after the comma `,` separating elements in the list + +```python +a = [1, 2, 3] # recommended +b = [1,2,3] # non-recommended +``` + +- Keep only **one space** before and after the comprehension expression token `for` and `in` in the dict and list. + +```python +a = [i for i in range(10)] # recommended +b = [i for i in range(10)] # non-recommended +``` + +## Slice + +- Keep the same number of spaces before and after the colon `:` of the list slice. + +```python +l = [1, 2, 3] +a = l[0:2] # recommended +b = l[0 : 2] # non-recommended +c = l[0: 2] # non-recommended + +d = l[0 + 0 : 1 + 1] # recommended +e = l[0 + 0:1 + 1] # non-recommended +``` + +## Schema + +- Leave only one space before and after the schema attribute assignment `=`. +- Always add a doc string to a schema, which is a good programming habit. + +```python +schema Person: + """ + Schema doc string + """ + name: str = "Alice" # recommended + age : int=12 # non-recommended + +person = Person {} +``` + +- Keep **no spaces** around the schema inheritance operator `()` + +```python +schema Base: + name: str + +schema Person(Base): # recommended + age: int + +schema Schema ( Base ): # non-recommended + age: int +``` + +- Keep **only one space** between the brackets and the schema name of the config at schema instantiation. + +```python +schema Base: + name: str + +schema Person(Base): + age: int + +personA = Person{} # non-recommended +personB = Person {} # recommended +``` + +- Keep **only one space** between the **mixin** keyword and the following `[]` operator + +```python +schema NameMixin: + name: str = "name" + +schema Person: + mixin [NameMixin] # non-recommended + age: int + +schema Parent: + mixin [NameMixin] # recommended + age: int +``` + +### Attribute Annotations + +- Annotations for schema attributes should have a single space after the colon `:` and no space before the colon `:`. + +```python +# recommended: +schema Person: + name: str # No space before the colon `:` + age: int = 18 # Spaces around assignment`=` +``` + +```python +# non-recommended: +schema Person: + codeA:int # No space after the colon `:` + codeB : int # Space before the colon `:` + name: str="Alice" # No spaces around assignment`=` +``` + +- There are no spaces around the colon `:` in the dict type annotation. + +```python +schema Person: + labels: {str:str} # recommended + keyValues: {str : str} # non-recommended +``` + +### Arguments + +- There are no spaces around the assignment `=` in the function/schema/decorator keyword arguments (kwargs). + +```python +schema Person[nameVar]: + # Decorator kwargs + @deprecated(strict=False) # recommended + name: str = nameVar + + @deprecated(strict = False) # non-recommended + age: int + +# Schema kwargs +personA = Person(nameVar="Alice") {} # recommended +personB = Person(nameVar = "Bob") {} # non-recommended + +# Function kwargs +print("", end='') # recommended +print("", end = '') # non-recommended +``` + +### Index Signature + +- It is recommended to place the schema index signature before the schema attribute instead of mixed placement. + +```python +schema ConfigReCommended: + [...str]: str # recommended + name: str + image: str + +schema ConfigNonReCommended: + name: str + [...str]: str # non-recommended + image: str +``` + +## Keywords + +- Only one space is usually reserved around the keyword, such as `schema`, `mixin`, `is` and `not`, etc. + +```python +schema NameMixin: + check: + name not None + +schema Person: + """ + Person schema definition + """ + mixin [NameMixin] + + name: str = "Alice" + age: int + +person = Person { + age = 18 +} +``` + +## Function + +- There are no spaces around the function/package select operator `.` +- There are no spaces between the function name and the parentheses `()`. + +```python +import math + +print(math.log(10)) # recommended +print( math . log (10)) # non-recommended +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/datatypes.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/datatypes.md new file mode 100644 index 000000000..ef7ea71af --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/datatypes.md @@ -0,0 +1,452 @@ +--- +title: "Data Types" +linkTitle: "Data Types" +type: "docs" +weight: 2 +description: Data Types +--- + +## Syntax + +### Bool + +Boolean values are the two constant objects `False` and `True`. They are used to represent truth values (although other values can also be considered false or true). The built-in function bool() can be used to convert any value to a Boolean, if the value can be interpreted as a truth value. + +### Int + +Int, or integer, is an arbitrarily sized integer, positive or negative, without decimals, of 64 binary digits precision(-9,223,372,036,854,775,808~9,223,372,036,854,775,807). Int is created by int literals or as the result of built-in functions and operators. Unadorned integer literals (including `hex`, `octal` and `binary` numbers) yield integers. The constructor int() can be used to produce int of a specific type. + +Besides, integer literals may have an `SI` or `IEC` multiplier. + +- `SI`: General integer or fixed-point number form: `P`, `T`, `G`, `M`, `K`, `k`, `m`, `u`, `n`. +- `IEC`: Corresponding power of 2: `Pi`, `Ti`, `Gi`, `Mi`, `Ki`. + +```python +a = 1 # positive integer: 1 +b = -1 # negative integer: -1 +c = 0x10 # hexadecimal literal: 16 +d = 0o10 # octal literal: 8, or the form `010` +e = 0b10 # binary literal: 2 +f = 10Ki # integer literal with IEC multiplier: 10240 +g = 1M # integer literal with SI multiplier: 1000000 +h = int("10") # int constructor: 10 +i = int("10Ki") # int constructor with multiplier: 10240 +``` + +Notes: + +- Report an error if unable to represent an integer value precisely. + +### Float + +Float, floating-point, approximation to real numbers, positive or negative, containing one or more decimals, of 64 bit IEEE 754 floats. The constructor float() can be used to produce int of a specific type. + +```python +a = 1.10 +b = 1.0 +c = -35.59 +d = 32.3+e18 +f = -90. +g = -32.54e100 +h = 70.2-E12 +i = float("112") # float constructor +``` + +Notes: + +- Report an error if unable to represent a floating-point value due to overflow +- Report a warning if unable to represent a floating-point value due to underflow. Round to the nearest representable value if unable to represent a floating-point value due to limits on precision. These requirements apply to the result of any expression except for built-in functions for which an unusual loss of precision must be explicitly documented. + +#### None + +In KCL, `None` can indicate that the value of the object is empty, which is similar to `nil` in Go or `null` in Java, and corresponds to `null` in YAML and JSON. + +```python +a = None +b = [1, 2, None] +c = {"key1" = "value1", "key2" = None} +``` + +Please note that `None` cannot participate in the four arithmetic operations, but it can participate logical operators and comparison operators to perform calculations. + +```python +a = 1 + None # error +b = int(None) # error +c = not None # True +d = None == None # True +e = None or 1 # 1 +f = str(None) # None +``` + +#### Undefined + +`Undefined` is similar to None, but its semantics is that a variable is not assigned any value and will not be output to YAML or JSON. + +```python +a = Undefined +b = [1, 2, Undefined] +c = {"key1" = "value1", "key2" = Undefined} +``` + +Please note that `Undefined` cannot participate in the four arithmetic operations, but it can participate logical operators and comparison operators to perform calculations. + +```python +a = 1 + Undefined # error +b = int(Undefined) # error +c = not Undefined # True +d = Undefined == Undefined # True +e = Undefined or 1 # 1 +f = str(Undefined) # Undefined +``` + +### Common Numeric Operations + +Int and Float support the following operations (see built-in proposal for built-in details): + +- `x + y`: sum of x and y. +- `x - y`: difference of x and y. +- `x * y`: product of x and y. +- `x / y`: quotient of x and y. +- `x // y`: floored quotient of x and y. +- `x % y`: remainder of x / y. +- `x ** y`: x to the power y. +- `-x`: x negated. +- `+x`: x unchanged. +- `~x`: x bitwise negation. +- `abs(x)`: absolute value or magnitude of x. +- `int(x)`: x converted to integer. +- `float(x)`: x converted to floating point. + +KCL supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the "narrower" type is widened to that of the other, where integer is narrower than floating-point. + +### String + +Strings are immutable sequences of Unicode characters. String literals are written in a variety of ways: + +```python +'allows embedded "double" quotes' # Single quotes +"allows embedded 'single' quotes" # Double quotes +'''Three single quotes''', """Three double quotes""" # Triple quoted +``` + +Triple quoted strings may span multiple lines. + +Indexing a string produces strings of length 1, for a non-empty string s, `s[0] == s[0:1]`. + +```python +a = "Hello, World!" +b = a[2:5] # "llo" +c = a[-5:-2] # "orl" +d = a[::-1] # "'!dlroW ,olleH'" +``` + +- `str(x=None) -> str` + +Return a string. If _x_ is not provided, raise a runtime error. + +```python +x = str(3.5) # "3.5" +``` + +#### Members + +Built-in function and members of a string + +- `str#len() -> int` + Return the number of characters in the string. +- `capitalize() -> str` + Return a copy of the string with its first character (if any) capitalized and the rest lowercased. +- `count(sub: str, start: int = 0, end: int = -1) -> int` + Returns the number of (non-overlapping) occurrences of substring sub in string, optionally restricting to `[start:end]`, start being inclusive and end being exclusive. +- `endswith(suffix: str, start: int = 0, end: int = -1) -> bool` + Returns `True` if the string ends with the specified suffix, otherwise return `False`, optionally restricting to `[start:end]`, start being inclusive and end being exclusive. +- `find(sub: str, start: int = 0, end: int = -1) -> int` + Returns the lowest index where substring sub is found, or -1 if no such index exists, optionally restricting to `[start:end]`, start being inclusive and end being exclusive. +- `format(*args, **kwargs) -> str` + Perform string interpolation. Format strings contain replacement fields surrounded by curly braces {}. Anything that is not contained in braces is considered literal text, which is copied unchanged to the output. If you need to include a bracket character in the literal text, it can be escaped by doubling: A replacement field can be either a name, a number or empty. Values are converted to strings using the str function. +- `index(sub: str, start: int = 0, end: int = -1) -> int` + Returns the first index where sub is found, or raises an error if no such index exists, optionally restricting to `[start:end]` start being inclusive and end being exclusive. +- `isalnum() -> bool` + Returns True if all characters in the string are alphanumeric (`[a-zA-Z0-9]`) and there is at least one character, False otherwise. +- `isalpha() -> bool` + Returns True if all characters in the string are alphabetic (`[a-zA-Z]`) and there is at least one character. +- `isdigit() -> bool` + Returns True if all characters in the string are digits (`[0-9]`) and there is at least one character. +- `islower() -> bool` + Returns True if all cased characters in the string are lowercase and there is at least one character. +- `isspace() -> bool` + Returns True if all characters are white space characters and the string contains at least one character. +- `istitle() -> bool` + Returns True if the string is in title case and it contains at least one character. This means that every uppercase character must follow an uncased one (e.g., whitespace) and every lowercase character must follow a cased one (e.g., uppercase or lowercase). +- `isupper() -> bool` + Returns True if all cased characters in the string are uppercase and there is at least one character. +- `join(iterable: list) -> str` + Return a string which is the concatenation of the strings in iterable. A TypeError will be raised if there are any non-string values in iterable. The separator between elements is the string providing this method. Example: + + ```python + >>> "|".join(["a", "b", "c"]) + "a|b|c" + ``` + +- `lower() -> str` + Returns a copy of the string with all the cased characters converted to lowercase. +- `lstrip(chars: str) -> str` + Return a copy of the string with leading characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix; rather, all combinations of its values are stripped: + + ```python + >>> ' spacious '.lstrip() + 'spacious ' + >>> 'www.example.com'.lstrip('cmowz.') + 'example.com' + ``` + +- `replace(old: str, new: str, count: int) -> str` + Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced. +- `rfind(sub: str, start: int = 0, end: int = -1) -> int` + Return the highest index in the string where substring sub is found, such that sub is contained within s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 on failure. +- `rindex(sub: str, start: int = 0, end: int = -1) -> int` + Returns the last index where sub is found, or raises an ValueError if no such index exists, optionally restricting to `[start:end]`, start being inclusive and end being exclusive. +- `rsplit(sep: str, maxsplit: int = -1) -> list` + Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done, the rightmost ones. If sep is not specified or None, any whitespace string is a separator. Except for splitting from the right, rsplit() behaves like split() which is described in detail below. +- `rstrip(chars: str) -> str` + Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped: + + ```python + >>> ' spacious '.rstrip() + ' spacious' + >>> 'mississippi'.rstrip('ipz') + 'mississ' + ``` + +- `split(sep: str, maxsplit: int) -> list` + Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). If maxsplit is not specified or -1, then there is no limit on the number of splits (all possible splits are made). + + If sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, `'1,,2'.split(',')` returns `['1', '', '2']`). The sep argument may consist of multiple characters (for example, `'1<>2<>3'.split('<>')` returns `['1', '2', '3']`). Splitting an empty string with a specified separator returns `['']`. + + For example: + + ```python + >>> '1,2,3'.split(',') + ['1', '2', '3'] + >>> '1,2,3'.split(',', maxsplit=1) + ['1', '2,3'] + >>> '1,2,,3,'.split(',') + ['1', '2', '', '3', ''] + ``` + + If sep is not specified or is None, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace. Consequently, splitting an empty string or a string consisting of just whitespace with a `None` separator returns `[]`. + + For example: + + ```python + >>> '1 2 3'.split() + ['1', '2', '3'] + >>> '1 2 3'.split(maxsplit=1) + ['1', '2 3'] + >>> ' 1 2 3 '.split() + ['1', '2', '3'] + ``` + +- `splitlines(keepends: str) -> list` + Return a list of the lines in the string, breaking at line boundaries('\n', '\r\n', '\r'). Line breaks are not included in the resulting list unless keepends is given and true. + + This method splits on the following line boundaries. In particular, the boundaries are a superset of universal newlines. + + For example: + + ```python + >>> 'ab c\n\nde fg\rkl\r\n'.splitlines() + ['ab c', '', 'de fg', 'kl'] + >>> 'ab c\n\nde fg\rkl\r\n'.splitlines(keepends=True) + ['ab c\n', '\n', 'de fg\r', 'kl\r\n'] + ``` + + Unlike `split()` when a delimiter string sep is given, this method returns an empty list for the empty string, and a terminal line break does not result in an extra line: + + ```python + >>> "".splitlines() + [] + >>> "One line\n".splitlines() + ['One line'] + ``` + + For comparison, `split('\n')` gives: + + ```python + >>> ''.split('\n') + [''] + >>> 'Two lines\n'.split('\n') + ['Two lines', ''] + ``` + +- `startswith(prefix: str, start: int = 0, end: int = -1) -> bool` + Return `True` if string starts with the prefix, otherwise return False. prefix can also be a list of prefixes to look for. With optional start, test string beginning at that position. With optional end, stop comparing string at that position. +- `strip(chars: str) -> str` + Return a copy of the string with the leading and trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix or suffix; rather, all combinations of its values are stripped: + + ```python + >>> ' spacious '.strip() + 'spacious' + >>> 'www.example.com'.strip('cmowz.') + 'example' + ``` + + The outermost leading and trailing chars argument values are stripped from the string. Characters are removed from the leading end until reaching a string character that is not contained in the set of characters in chars. A similar action takes place on the trailing end. For example: + + ```python + >>> comment_string = '#....... Section 3.2.1 Issue #32 .......' + >>> comment_string.strip('.#! ') + 'Section 3.2.1 Issue #32' + ``` + +- `title() -> str` + Return a titlecased version of the string where words start with an uppercase character and the remaining characters are lowercase. + + For example: + + ```python + >>> 'Hello world'.title() + 'Hello World' + ``` + + The algorithm uses a simple language-independent definition of a word as groups of consecutive letters. The definition works in many contexts but it means that apostrophes in contractions and possessives form word boundaries, which may not be the desired result: + + ```python + >>> "they're bill's friends from the UK".title() + "They'Re Bill'S Friends From The Uk" + ``` + +- `upper() -> str` + Return a copy of the string with all the cased characters 4 converted to uppercase. Note that `s.upper().isupper()` might be `False` if s contains uncased characters or if the Unicode category of the resulting character(s) is not “Lu” (Letter, uppercase), but e.g., “Lt” (Letter, titlecase). +- `removeprefix(prefix: str) -> str` + If the string starts with the prefix string, return string[len(prefix):]. Otherwise, return a copy of the original string. + ```python + >>> "prefix-data".removeprefix("prefix-") + "data" + ``` +- `rermovesuffix(suffix: str) -> str` + If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. Otherwise, return a copy of the original string. + ```python + >>> "data-suffix".removesuffix("-suffix") + "data" + ``` + +### List + +Lists are immutable sequences, typically used to store collections of homogeneous items (where the precise degree of similarity will vary by application). + +Lists may be constructed in several ways: + +- Using a pair of square brackets to denote the empty list: `[]` +- Using square brackets, separating items with commas: `[a]`, `[a, b, c]` +- Using a list comprehension: `[x for x in iterable]` +- Using the type constructor: list() or list(iterable) + +The constructor builds a list whose items are the same and in the same order as iterable’s items.Iterable may be either a sequence, a container that supports iteration, or an iterator object. If iterable is already a list, a copy is made and returned, similar to `iterable[:]`. For example, `list('abc')` returns `['a', 'b', 'c']` and `list([1, 2, 3])` returns `[1, 2, 3]`. If no argument is given, the constructor creates a new empty list `[]`. + +Lists implement all of the common sequence operations. + +#### Members + +- `len()` + Return the number of items in the list. + +### Common Sequence Operations + +The operations in the following table are supported by List and Dict. + +This table lists the sequence operations sorted in ascending priority. In the table, s and t are sequences of the same type, n, i, j and k are integers and x is an arbitrary object that meets any type and value restrictions imposed by s. + +The `in` and `not in` operations have the same priorities as the comparison operations. The + +(concatenation) and \* (repetition) operations have the same priority as the corresponding numeric operations. + +| Operation | Result | Notes | +| ------------ | -------------------------------------------------- | ----- | +| `x in s` | `True` if an item of s is equal to x, else `False` | #1 | +| `x not in s` | `False` if an item of s is equal to x, else `True` | #1 | +| `s + t` | the concatenation of s and t | #5 | +| `s[i]` | ith item of s, origin 0 | #2 | +| `s[i:j]` | slice of s from i to j | #2 #3 | +| `s[i:j:k]` | slice of s from i to j with step k | #2 #4 | +| `min(s)` | smallest item of s | | +| `max(s)` | largest item of s | | + +Notes: + +- 1. While the in and not in operations are used only for simple containment testing in the + general case, some specialized sequences (str) also use them for subsequence testing: + +```python +>>> "gg" in "eggs" +True +``` + +- 2. If i or j is negative, the index is relative to the end of sequence s: `s.len() + i` or `s.len() + j` is substituted. But note that -0 is still 0. +- 3. The slice of s from i to j is defined as the sequence of items with index k such that `i <= k < j`. If i or j is greater than `s.len()`, use `s.len()`. If i is omitted or None, use 0. If j is omitted or None, use `s.len()`. If i is greater than or equal to j, the slice is empty. +- 4. The slice of s from i to j with step k is defined as the sequence of items with index `x = i + n*k` such that `0 <= n < (j-i)/k`. In other words, the indices are `i`, `i+k`, `i+2*k`, `i+3*k` and so on, stopping when j is reached (but never including j). When k is positive, i and j are reduced to s.len() if they are greater. When k is negative, i and j are reduced to s.len() + + - If they are greater. If i or j are omitted or None, they become “end” values (which end depends on the sign of k). Note, k cannot be zero. If k is None, it is treated like 1. + +- 5. Concatenating immutable sequences always results in a new object. This means that building up a sequence by repeated concatenation will have a quadratic runtime cost in the total sequence length. To get a linear runtime cost, you must switch to one of the alternatives below: + + - if concatenating str objects, you can build a list and use `str.join()` at the end + +- 6. `index` raises `ValueError` when x is not found in s. Not all implementations support passing the additional arguments i and j. These arguments allow efficient searching of subsections of the sequence. Passing the extra arguments is roughly equivalent to using `s[i:j].index(x)`, only without copying any data and with the returned index being relative to the start of the sequence rather than the start of the slice. + +### Dict + +Dict is an immutable mapping object maps hashable values to arbitrary objects. A dictionary’s keys are almost arbitrary values. Values that are not hashable, that is, values containing lists, dictionaries may not be used as keys. Numeric types used for keys obey the normal rules for numeric comparison: if two numbers compare equal (such as 1 and 1.0) then they can be used interchangeably to index the same dictionary entry. (Note however, that since computers store floating-point numbers as approximations it is usually unwise to use them as dictionary keys.) Dict is ordered. The order of the keys is the order of their declaration. + +Dictionaries can be created by placing a comma-separated list of keys: value pairs within braces, for example: `{'jack': 4098, 'sjoerd': 4127}` or `{4098: 'jack', 4127: 'sjoerd'}`, by the dict constructor, or list/dict comprehension. + +- `dict(obj)` + +Return a new dictionary initialized from an optional positional argument and a possibly empty set of keyword arguments.If no positional argument is given, an empty dictionary is created. If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, the positional argument must be an iterable object. Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value. If a key occurs more than once, the last value for that key becomes the corresponding value in the new dictionary. If keyword arguments are given, the keyword arguments and their values are added to the dictionary created from the positional argument. If a key being added is already present, the value from the keyword argument replaces the value from the positional argument. To illustrate, the following examples all return a dictionary equal to `{"one": 1, "two": 2, "three": 3}`: + +```python +>>> a = {'two': 2, 'one': 1, 'three': 3} +>>> b = {'one': 1, 'two': 2, 'three': 3} +>>> c = {'three': 3, 'one': 1, 'two': 2} +>>> a == b == c +True +``` + +Providing keyword arguments as in the first example only works for keys that are valid KCL identifiers. Otherwise, any valid keys can be used. + +In the dict comprehension, key/value pairs yielded by the generator expression is set in the dictionary in the order yielded: the first occurrence of the key determines its insertion order, and the last determines the value associated to it. + +```python +>>> {str(i): 2 * i for i in range(3)} +{"0": 0, "1": 2, "2": 4} + +>>> a = {"one": 1, "two": 2, "three": 3} +>>> b = {k: v for k, v in a if v >= 2} +{two: 2, three: 3} +``` + +#### Operations & Members + +These are the operations that dictionaries the support. + +- `list(d)` + Return a list of all the keys used in the dictionary d. +- `len()` + Return the number of items in the dictionary d. +- `d[key]` + Return the item of d with key. Return Undefined if key is not in the map. +- `key in d` + Return True if d has a key, else False. +- `key not in d` + Equivalent to not key in d. +- `d.key` + Return the item of d with key. Return Undefined if key is not in the map. + +Dictionaries compare equal if and only if they have the same (key, value) pairs(keys' ordering matters). Order comparisons (‘<’, ‘<=’, ‘>=’, ‘>’) raise TypeError. + +```python +>>> d = {"one": 1, "two": 2, "three": 3, "four": 4} +>>> d +{'one': 1, 'two': 2, 'three': 3, 'four': 4} +>>> list(d) +['one', 'two', 'three', 'four'] +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/error.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/error.md new file mode 100644 index 000000000..65420a2fc --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/error.md @@ -0,0 +1,53 @@ +--- +title: "Errors" +linkTitle: "Errors" +type: "docs" +weight: 2 +description: Errors +--- + +When errors happen, developers should be able to detect the error and abort +execution. Thus, KCL introduce the `assert` syntax. + +In the previous topic of `schema` syntax. Errors can also be raised when a +schema is violated. + +## Syntax + +The syntax of the `assert` statement is the following. + +```bnf +assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? +``` + +In the basic form, an `assert` statement evaluates an expression. If the +expression is evaluated to `False`, the assertion is failed, and an error +should be reported. + +In the extended form, an error message can be provided. The error message is +another expression. It is only evaluated when the expression to be evaluated +is evaluated to `False`. The evaluation result of the error message is printed +when reporting the error. + +The following is an example: + +```python +a = 1 +b = 3 +condition = False +# a != b evaluates to True, therefore no error should happen. +assert a != b +# a == b is False, in the reported error message, the message "SOS" should be printed. +assert a == b, "SOS" +# if condition is True, then assert `a == b`, if failed, the message "error message" will be printed. +assert a == b if condition, "error message" +``` + +## The Implementation + +When an error happens, no matter it is caused by the `assert` or the `schema` syntax, +the virtual machine should exit with an exit code greater than `0`. + +The virtual machine may choose to dump the back trace information, and it is strongly recommended to implement it. + +In practice, KCL can dump back trace by default, and an argument can be introduced to disable it. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/expressions.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/expressions.md new file mode 100644 index 000000000..b52c10f3f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/expressions.md @@ -0,0 +1,915 @@ +--- +title: "Expressions" +linkTitle: "Expressions" +type: "docs" +weight: 2 +description: Expressions +--- + +## Syntax + +In KCL, an expression specifies the computation of a value. + +The syntax is the following: + +```bnf +expression: test ("," test)* +test: if_expr | primary_expr | unary_expr | binary_expr +``` + +KCL expressions consist of `if` expression, `primary` expression, `unary` expression, and `binary` expression. + +### Primary Expressions + +Primary expressions are the operands for unary and binary expressions. + +Operands are self-delimiting. An **operand** may be followed by any number of selector dot, a function call, or slice suffixes, to form a primary expression. The grammar uses `expression`, where a multiple-component expression is allowed, and `test` where it accepts an expression of only a single component. + +Syntax: + +```bnf +primary_expr: operand | primary_expr select_suffix | primary_expr call_suffix | primary_expr subscript_suffix +``` + +### Operands + +Operand denotes the elementary value in an expression. An operand may be an identifier, a literal, or a parenthesized expression. + +Syntax: + +```bnf +operand: operand_name | number | string | "True" | "False" | "None" | "Undefined" | list_expr | list_comp | dict_expr | dict_comp | "(" expression ")" +operand_name: identifier | qualified_identifier +``` + +### Identifiers + +In KCL, an identifier is a name, may with selectors, that identifies a value. + +Syntax: + +```bnf +identifier: NAME +``` + +Examples: + +```python +x +a +_b +``` + +Use the `$` character prefix to define keyword identifiers. + +```python +$if = 1 +$else = "s" +``` + +Please note: whether the non-keyword identifier is prefixed with `$` has the same effect. + +```python +_a = 1 +$_a = 2 # equal to `_a = 2` +``` + +To simplify the definition of the qualified identifier, such as 'pkg.type', we additionally define `qualified_identifier`: + +Syntax: + +```bnf +qualified_identifier: identifier "." identifier +``` + +Examples: + +```python +pkg.a +``` + +The package name in qualified_identifier must be imported. + +### Basic Literals + +Basic literals supported in KCL are `int`, `float`, `string` and `bool` including `True` and `False`. Evaluation of basic literal yields a value of the given type with the given value. + +Syntax: + +```bnf +operand: number | string | "True" | "False" | "None" | "Undefined" +``` + +Examples: + +```python +1 +2.3 +"abc" +True +False +None +Undefined +``` + +See more details about **data type** spec. + +### Parenthesized Expressions + +An expression enclosed in parentheses yields the result of that expression. + +Syntax: + +```bnf +operand: '(' expression ')' +``` + +Examples: + +```python +x = (1 + 2) * (3 + 4) # 21 +``` + +### Dictionary Expressions + +A dictionary expression is a comma-separated immutable list of colon-separated key/value expression pairs, enclosed in curly brackets, and it yields a new dictionary object. An optional comma may follow the final pair. + +```bnf +config_expr: '{' config_entries '}' +config_entries: config_entry [config_entry*] +config_comp: '{' (config_entry comp_clause+) '}' +config_entry: expr (':' | '=' | '+=') expr | double_star_expr | if_entry +double_star_expr: "**" expression +if_entry: + 'if' expr ';' if_entry_exec_block + ('elif' expr ':' if_entry_exec_block)* + ('else' ':' if_entry_exec_block)? +NEWLINE: '/r?/n' +``` + +Examples: + +```python +{} +{"one": 1} +{"one": 1, "two": 2} +``` + +The key and value expressions are evaluated in left-to-right order. Evaluation fails if the same key is used multiple times. + +Only hashable values may be used as the keys of a dictionary. This includes all built-in types except dictionaries, and lists. + +We can ignore the comma `,` at the end of the line for writing dict key-value pairs in multiple lines: + +```python +data = { + "key1" = "value1" # Ignore the comma ',' at the end of line + "key2" = "value2" +} # {"key1": "value1", "key2": "value2"} +``` + +We can ignore the key quotation marks when we writing simple literals on the key. + +```python +data = { + key1 = "value1" # Ignore the comma ',' at the end of line + key2 = "value2" +} # {"key1": "value1", "key2": "value2"} +``` + +In addition, the **config selector expressions** can be used to init a schema instance. + +```python +person = { + base.count = 2 + base.value = "value" + labels.key = "value" +} # {"base": {"count": 2, "value": "value"}, "labels": {"key": "value"}} +``` + +We can **merge** dict using the dict unpacking operator `**` like this: + +```python +_part1 = { + a = "b" +} + +_part2 = { + c = "d" +} + +a_dict = {**_part1, **_part2} # {"a: "b", "c": "d"} +``` + +We can use `if expressions` to dynamically add elements to the dict element, elements that meet the conditions are added to the dict, and elements that do not meet the conditions are ignored. + +```python +a = 1 # 1 +data = { + key1 = "value1" + if a == 1: key2 = "value2" + if a > 0: key3 = "value3" + if a < 0: key4 = "value4" +} # {"key1": "value1", "key2": "value2", "key3": "value3"} +``` + +```python +a = 1 # 1 +data1 = { + key1 = "value1" + if a == 1: + key2 = "value2" + elif a > 0: + key3 = "value3" + else: + key4 = "value4" +} # {"key1": "value1", "key2": "value2"} +data2 = { + key1 = "value1" + if a == 1: key2 = "value2" + elif a > 0: key3 = "value3" + else: key4 = "value4" +} # {"key1": "value1", "key2": "value2"} +``` + +### List Expressions + +A list expression is a comma-separated immutable list of element expressions, enclosed in square brackets, and it yields a new list. An optional comma may follow the last element expression. + +```bnf +list_expr: '[' [list_item [',']] ']' +list_item: test | "*" primary_expr | if_expr +``` + +Element expressions are evaluated in left-to-right order. + +Examples: + +```python +[] # [], empty list +[1] # [1], a 1-element list +[1, 2, 3] # [1, 2, 3], a 3-element list +``` + +We can use `if expressions` to dynamically add elements to the list element, elements that meet the conditions are added to the list, and elements that do not meet the conditions are ignored. + +```python +a = 1 # 1 +data = [ + 1 + if a == 1: 2 + if a > 0: 3 + if a < 0: 4 +] # [1, 2, 3] +``` + +```python +a = 1 # 1 +data1 = [ + 1 + if a == 1: + 2 + elif a == 2: + 3 + else: + 3 +] # [1, 2] +data2 = [ + 1 + if a == 1: 2 + elif a == 2: 2 + else: 3 +] # [1, 2] +``` + +### Comprehensions + +A comprehension constructs a new list or dictionary value by looping over one or more iterables and evaluating a body expression that produces successive elements of the result. + +Syntax: + +```bnf +list_comp: '[' list_item comp_clause+ ']' . +dict_comp: '{' entry comp_clause+ '}' . + +comp_clause: 'for' loop_variables [","] 'in' test ['if' test] +loop_variables: primary_expr (',' primary_expr)* +``` + +A list comprehension consists of a single expression followed by one or more clauses, the first of which must be a `for` clause. Each `for` clause resembles a `for` statement, and specifies an iterable operand and a set of variables to be assigned by successive values of the iterable. An `if` cause resembles an `if` statement, and specifies a condition that must be met for the body expression to be evaluated. A sequence of `for` and `if` clauses acts like a nested sequence of `for` and `if` statements. + +Examples: + +```python +[x * x for x in range(5)] # [0, 1, 4, 9, 16] +[x * x for x in range(5) if x % 2 == 0] # [0, 4, 16] +[[x, y] for x in range(5) \ + if x % 2 == 0 \ + for y in range(5) \ + if y > x] # [[0, 1], [0, 2], [0, 3], [0, 4], [2, 3], [2, 4]] +``` + +Besides, we can use two variables in the list comprehension, the first variable denotes the list index and the second variable denotes the list item. + +```python +data = [1000, 2000, 3000] +# Single variable loop +dataLoop1 = [i * 2 for i in data] # [2000, 4000, 6000] +dataLoop2 = [i for i in data if i == 2000] # [2000] +dataLoop3 = [i if i > 2 else i + 1 for i in data] # [1000, 2000, 3000] +# Double variable loop +dataLoop4 = [i + v for i, v in data] # [1000, 2001, 3002] +dataLoop5 = [v for i, v in data if v == 2000] # [2000] +# Use `_` to ignore loop variables +dataLoop6 = [v if v > 2000 else v + i for i, v in data] # [1000, 2001, 3000] +dataLoop7 = [i for i, _ in data] # [0, 1, 2] +dataLoop8 = [v for _, v in data if v == 2000] # [2000] +``` + +A dict comprehension resembles a list comprehension, but its body is a pair of expressions, key: value, separated by a colon, and its result is a dictionary containing the key/value pairs for which the body expression was evaluated. Evaluation fails if the value of any key is un-hashable. + +Besides, we can use two variables in the dict comprehension, the first variable denotes the dict key and the second variable denotes the dict value of the key. + +```python +data = {"key1" = "value1", "key2" = "value2"} +# Single variable loop +dataKeys1 = {k: k for k in data} # {"key1": "key1", "key2": "key2"} +dataValues1 = {k: data[k] for k in data} # {"key1": "value1", "key2": "value2"} +# Double variable loop +dataKeys2 = {k: k for k, v in data} # {"key1": "key1", "key2": "key2"} +dataValues2 = {v: v for k, v in data} # {"value1": "value1", "value2": "value2"} +dataFilter = {k: v for k, v in data if k == "key1" and v == "value1"} # {"key1": "value1"} +# Use `_` to ignore loop variables +dataKeys3 = {k: k for k, _ in data} # {"key1": "key1", "key2": "key2"} +dataValues3 = {v: v for _, v in data} # {"value1": "value1", "value2": "value2"} +``` + +As with a `for` loop, the loop variables may exploit compound assignment: + +```python +[x * y + z for [x, y], z in [[[2, 3], 5], [["o", 2], "!"]]] # [11, 'oo!'] +``` + +KCL does not accept an un-parenthesized list as the operand of a for clause: + +```python +[x * x for x in 1, 2, 3] # parse error: unexpected comma +``` + +Comprehensions defines a new lexical block, so assignments to loop variables have no effect on variables of the same name in an enclosing block: + +```python +x = 1 +_ = [x for x in [2]] # new variable x is local to the comprehension +print(x) # 1 +``` + +The operand of a comprehension's first clause (always a for) is resolved in the lexical block enclosing the comprehension. In the examples below, identifiers referring to the outer variable named x have been distinguished by subscript. + +```python +x0 = [1, 2, 3] +[x * x for x in x0] # [1, 4, 9] +[x * x for x in x0 if x % 2 == 0] # [4] +``` + +All subsequent for and if expressions are resolved within the comprehension's lexical block, as in this rather obscure example: + +```python +x0 = [[1, 2], [3, 4], [5, 6]] +[x * x for x in x0 for x in x if x % 2 == 0] # [4, 16, 36] +``` + +which would be more clearly rewritten as: + +```python +x = [[1, 2], [3, 4], [5, 6]] +[z * z for y in x for z in y if z % 2 == 0] # [4, 16, 36] +``` + +### Conditional Expressions + +A conditional expression has the form `a if cond else b`. It first evaluates the condition `cond`. If it's true, it evaluates `a` and yields its value; otherwise it yields the value of `b`. + +Syntax: + +```bnf +if_expr: test "if" test "else" test +``` + +Examples: + +```python +x = True if enabled else False # if enabled is +``` + +### Unary Expressions + +In KCL, supported unary operators are `+`, `-`, `~`, and `not`. + +Syntax: + +```bnf +unary_expr: ("+" | "-" | "~") primary_expr + | "not" test +``` + +Usage: + +```bnf ++ number unary positive (int, float) +- number unary negation (int, float) +~ number unary bitwise inversion (int) +not x logical negation (any type) +``` + +The `+` and `-` operators may be applied to any number (int or float) and return the number. +The `not` operator returns the negation of the truth value of its operand. + +Examples: + +```python +~1 # -2 +~-1 # 0 +~0 # -1 +not True # False +not 0 # True +``` + +### Binary Expressions + +In KCL, binary expressions consist of `comparisons`, `logical operations`, `arithmetic operations` and `membership tests`. + +Syntax: + +```bnf +binary_expr: test bin_op test +bin_op: 'or' + | 'and' + | '==' | '!=' | '<' | '>' | '<=' | '>=' + | 'in' | 'not' 'in' + | '|' + | '^' + | '&' + | '-' | '+' + | '*' | '%' | '/' | '//' + | '<<' | '>>' +``` + +#### Logical Operations + +The `or` and `and` operators yield the logical disjunction and conjunction of their arguments, which need not be Booleans. + +The expression `x or y` yields the value of `x` if its truth value is `True`, or the value of `y` otherwise. + +```python +False or False # False +False or True # True +True or True # True +1 or "hello" # 1 +``` + +Similarly, `x` and `y` yields the value of `x` if its truth value is `False`, or the value of `y` otherwise. + +```python +False and False # False +False and True # False +True and True # True +1 and "hello" # "hello" +``` + +These operators use "short circuit" evaluation, so the second expression is not evaluated if the value of the first expression has already determined the result, allowing constructions like these: + +```python +x and x[0] == 1 # x[0] is not evaluated if x is empty +len(x) == 0 or x[0] == "" +not x or not x[0] +``` + +#### Comparisons + +The `==` operator reports whether its operands are equal; the `!=` operator is its negation. + +The operators `<`, `>`, `<=`, and `>=` perform an ordered comparison of their operands. It is an error to apply these operators to operands of unequal type, unless one of the operands is an `int` and the other is a `float`. Of the built-in types, only the following support ordered comparison, using the ordering relation shown: + +```bnf +NoneType # None <= None +bool # False < True +int # mathematical +float # as defined by IEEE 754 +string # lexicographical +list # lexicographical +``` + +Comparison of floating-point values follows the IEEE 754 standard, which breaks several mathematical identities. For example, if `x` is a `NaN` value, the comparisons `x < y`, `x == y`, and `x > y` all yield false for all values of `y`. + +The remaining built-in types support only equality comparisons. Values of type `dict` and `schema` compare equal if their elements compare equal, and values of type function or `builtin_function_or_method` are equal only to themselves. + +```bnf +dict # equal contents +schema # equal exported-attributes +function # identity +builtin_function_or_method # identity +``` + +#### Arithmetic Operations + +The following table summarizes the binary arithmetic operations available for built-in types: + +```bnf +Arithmetic (int or float; result has type float unless both operands have type int) + number + number # addition + number - number # subtraction + number * number # multiplication + number / number # real division (result is always a float) + number // number # floored division + number % number # remainder of floored division + number ^ number # bitwise XOR + number << number # bitwise left shift + number >> number # bitwise right shift + +Concatenation + string + string + list + list + +Repetition (string/list) + int * sequence + sequence * int + +Union + int | int + list | list + dict | dict + schema | schema + schema | dict +basictype | basictype +``` + +The operands of the arithmetic operators `+`, `-`, `*`, `//`, and `%` must both be numbers (`int` or `float`) but need not have the same type. The type of the result has type `int` only if both operands have that type. The result of real division / always has type `float`. + +The `+` operator may be applied to non-numeric operands of the same type, such as two lists, or two strings, in which case it computes the concatenation of the two operands and yields a new value of the same type. + +```python +"Hello, " + "world" # "Hello, world" +[1, 2] + [3, 4] # [1, 2, 3, 4] +``` + +The `*` operator may be applied to an integer n and a value of type `string`, `list`, in which case it yields a new value of the same sequence type consisting of n repetitions of the original sequence. The order of the operands is immaterial. Negative values of n behave like zero. + +```python +'mur' * 2 # 'murmur' +3 * range(3) # [0, 1, 2, 0, 1, 2, 0, 1, 2] +``` + +The `&` operator requires two operands of the same type, such as `int`. For integers, it yields the bitwise intersection (AND) of its operands. + +The `|` operator likewise computes bitwise, unions basic types and unions collection and schema data, such as **list**, **dict** and **schema**. + +Computing bitwise examples: + +```python +0x12345678 | 0xFF # 0x123456FF +``` + +Unioning basic types examples: + +```python +schema x: + a: int | str # attribute a could be a int or string +``` + +A union type is used to define a schema attribute type. See more details in **schema** spec. +Supported types in a union type are `int`, `str`, `float`, `bool`, `list` and `dict`. + +Unioning collection and schema data: + +- Unioning List. Overwrite the list expression on the right side of the operator `|` to the list variable on the left side of the operator one by one according to the **index**. + +```python +_a = [1, 2, 3] +_b = [4, 5, 6, 7] +x = _a | _b # [4, 5, 6, 7] 4 -> 1; 5 -> 2; 6 -> 3; 7 -> None +``` + +Unioning to the specific index or all elements is still under discussion. + +- Unioning Dict. Union the dict expression on the right side of the operator `|` one by one to the dict variable on the left side of the operator according to the **key** + +```python +_a = {key1 = "value1"} +_b = {key1 = "overwrite", key2 = "value2"} +_c = _a | _b # {"key1": "overwrite", "key2": "value2"} +``` + +The union of collection and schema is a new one whose attributes are unioning b to a, preserving the order of the attributes of the operands, left before right. + +Unioning to the specific key or all keys is still under discussion. + +- Unioning Schema. + +The union operation for schema is similar to dict. + +Schema union could be done as: + +```bnf +schema Person: + firstName: str + lastName: str + +_a = Person { + firstName = "John" +} +_b = {lastName = "Doe"} +_a = _a | _b # {"firstName": "John", "lastName": "Doe"} +``` + +Unioning to a specific attribute is still under discussion. Unioning to all attributes is not applicable to schema instances. + +See **selector expression** in **expression** spec for more details. + +The `^` operator accepts operands of `int`. For integers, it yields the bitwise XOR (exclusive OR) of its operands. + +The `<<` and `>>` operators require operands of `int` type both. They shift the first operand to the left or right by the number of bits given by the second operand. It is a dynamic error if the second operand is negative. Implementations may impose a limit on the second operand of a left shift. + +```python +0x12345678 & 0xFF # 0x00000078 +0b01011101 ^ 0b110101101 # 0b111110000 +0b01011101 >> 2 # 0b010111 +0b01011101 << 2 # 0b0101110100 +``` + +#### Membership Tests + +Usage: + +```bnf + any in sequence (list, dict, schema, string) + any not in sequence +``` + +The `in` operator reports whether its first operand is a member of its second operand, which must be a list, dict, schema, or string. The `not in` operator is its negation. Both return a Boolean. + +The meaning of membership varies by the type of the second operand: the members of a list are its elements; the members of a dict are its keys; the members of a string are all its substrings. + +```python +1 in [1, 2, 3] # True + +d = {"one" = 1, "two" = 2} +"one" in d # True +"three" in d # False +1 in d # False +[] in d # False + +"nasty" in "dynasty" # True +"a" in "banana" # True +"f" not in "way" # True + +d = data {one = 1, two = 2} # data is a schema with attributes one and two +"one" in d # True +"three" in d # False +``` + +### Function Invocations + +KCL allows calling built-in functions and functions from built-in and system modules. Whether KCL allows defining new functions is under discussion. + +Syntax: + +```bnf +call_suffix: "(" [arguments [","]] ")" +arguments: argument ("," argument)* +argument: test | identifier "=" test | "*" test | "**" test +``` + +To call a function, the basic way is shown as the following code excerpt: + +```python +print("An argument") + +import math +# 2 powers 3 is 8. +a = math.pow(2, 3) +``` + +As you can see, arguments are separated with `,`. Arguments can only be passed in this way. KCL supports positional arguments and key-value arguments. + +Note that: + +- Some functions have parameters with default values. +- Some functions accept variadic arguments. + +When an argument is not supplied for a parameter without a default value, +an error will be reported. + +### Selector Expressions + +A selector expression selects the attribute or method of the value. + +#### Select Attributes + +Syntax: + +```bnf +select_suffix: ["?"] "." identifier +``` + +KCL provides a wealth of ways to identify or filter attributes. + +x.y + +- schema: it denotes the attribute value of a schema `x` identified by `y` +- package: it denotes the identifier of a package `x` identified by `y` + +Examples: + +```python +schema Person: + name: str + age: int + +person = Person { + name = "Alice" + age = 18 +} +name = person.name # "Alice" +age = person.age # 18 +``` + +x?.y + +If the x if None/Undefined or empty(empty list or dict), just return None, otherwise behave as x.y. + +Examples + +```python +noneData = None +data?.name # None + +emptyDict = {} +emptyDict?.name # None + +emptyList = [] +emptyList?[0] # None +``` + +As a supplementary of the `selector` expression in KCL code, the KCL compiler needs to provide corresponding identifying and filtering features through the command line and api form. + +#### Select Methods + +Syntax: + +```bnf +select_suffix: "." identifier +``` + +A `identifier` identifies method belongs to the built-in types `string`, `list`, `dict`, and `schema`. + +- A selector expression fails if the value does not have an attribute of the specified name. +- A selector expression that selects a method typically appears within a call expression, as in these examples: + +Examples: + +```python +["able", "baker", "charlie"].index("baker") # 1 +"banana".count("a") # 3 +"banana".reverse() # error: string has no .reverse field or method +Person.instances() # all instances of schema Person +``` + +But when not called immediately, the selector expression evaluates to a bound method, that is, a method coupled to a specific receiver value. A bound method can be called like an ordinary function, without a receiver argument: + +```bnf +f = "banana".count +f # +f("a") # 3 +f("n") # 2 +``` + +### Index Expressions + +An index expression `a[i]` yields the `i` th element of an indexable type such as a string or list. The index `i` must be an `int` value in the range `-n` ≤ `i` < `n`, where `n` is `len(a)`; any other index results in an error. + +Syntax: + +```bnf +subscript_suffix: "[" [test] "]" +``` + +A valid negative index `i` behaves like the non-negative index `n+i`, allowing for convenient indexing relative to the end of the sequence. + +```python +"abc"[0] # "a" +"abc"[1] # "b" +"abc"[-1] # "c" + +["zero", "one", "two"][0] # "zero" +["zero", "one", "two"][1] # "one" +["zero", "one", "two"][-1] # "two" +``` + +An index expression `d[key]` may also be applied to a dictionary `d`, to obtain the value associated with the specified key. It returns `Undefined` if the dictionary contains no such key. + +An index expression appearing on the left side of an assignment causes the specified list or dictionary element to be updated: + +```python +a = range(3) # a == [0, 1, 2] +b = a[2] # 2 + + +``` + +It is a dynamic error to attempt to update an element of an immutable type, such as a list or string, or a frozen value of a mutable type. + +### Slice Expressions + +A slice expression `a[start:stop:stride]` yields a new value containing a sub-sequence of `a`, which must be a string, or list. + +```bnf +subscript_suffix: "[" [test] [":" [test] [":" [test]]] "]" +``` + +Each of the `start`, `stop`, and `stride` operands is optional; if present, and not `None`, each must be an integer. +The `stride` value defaults to 1. If the stride is not specified, the colon preceding it may be omitted too. It is an error to specify a stride of zero. + +Conceptually, these operands specify a sequence of values `i` starting at start and successively adding `stride` until `i` reaches or passes `stop`. The result consists of the concatenation of values of `a[i]` for which `i` is valid.` + +The effective start and stop indices are computed from the three operands as follows. Let `n` be the length of the sequence. + +**If the stride is positive**: If the `start` operand was omitted, it defaults to -infinity. If the `end` operand was omitted, it defaults to +infinity. For either operand, if a negative value was supplied, `n` is added to it. The `start` and `end` values are then "clamped" to the nearest value in the range 0 to `n`, inclusive. + +**If the stride is negative**: If the `start` operand was omitted, it defaults to +infinity. If the `end` operand was omitted, it defaults to -infinity. For either operand, if a negative value was supplied, `n` is added to it. The `start` and `end` values are then "clamped" to the nearest value in the range -1 to `n`-1, inclusive. + +```python +"abc"[1:] # "bc" (remove first element) +"abc"[:-1] # "ab" (remove last element) +"abc"[1:-1] # "b" (remove first and last element) +"banana"[1::2] # "aaa" (select alternate elements starting at index 1) +"banana"[4::-2] # "nnb" (select alternate elements in reverse, starting at index 4) +``` + +It's not allowed to define a slice expression as a left value in KCL. +Cause list and string are immutable, re-slicing can directly operate to operand to ensure better performance. + +#### Quantifier Expressions + +Quantifier expressions act on collection: list or dict, generally used to obtain a certain result after processing the collection, mainly in the following four forms: + +```bnf +quant_expr: quant_op [ identifier ',' ] identifier 'in' quant_target '{' expr ['if' expr] '}' +quant_target: string | identifier | list_expr |list_comp | dict_expr | dict_comp +quant_op: 'all' | 'any' | 'filter' | 'map' +``` + +- **all** + - Used to detect that all elements in the collection satisfy the given logical expression, and return a boolean value as the result. + - Only when all elements in the collection satisfy the expression true, the `all` expression is true, otherwise it is false. + - If the original collection is empty, return true. + - Supports short-circuiting of logical expressions during expression execution. +- **any** + - Used to detect that at least one element in the collection satisfies the given logical expression, and returns a boolean value as the result. + - When at least one element in the collection satisfies the expression true, the `any` expression is true, otherwise it is false. + - If the original collection is empty, return false. + - Supports short-circuiting of logical expressions during expression execution. +- **map** + - Generate a new **list** by mapping the elements in the original collection. + - The length of the new list is exactly the same as the original collection. +- **filter** + - By logically judging and filtering the elements in the original collection, and returning the filtered sub-collection. + - Only when the element judges the expression to be true, it is added to the sub-collection. + - The type (list, dict and schema) of the new collection is exactly the same as the original collection, and the length range is `[0, len(original-collection)]`. + +**all** and **any** expression sample codes: + +```python +schema Config: + volumes: [{str:}] + services: [{str:}] + + check: + all service in services { + service.clusterIP == "NONE" if service.type == "ClusterIP" + }, "invalid cluster ip" + + any volume in volumes { + volume.mountPath in ["/home/admin", "/home/myapp"] + } +``` + +**map** and **filter** expression sample codes: + +```python +a = map e in [{name = "1", value = 1}, {name = "2", value = 2}] { + {name = e.name, value = int(e.value) ** 2} +} # [{"name": "1", value: 1}, {"name": "2", "value": 4}] + +b = map k, v in {a = "foo", b = "bar"} { v } # ["foo", "bar"] + +c = filter e in [{name = "1", value = 1}, {name = "2", value = 2}] { + int(e.value) > 1 +} # [{"name": "2", "value": 2}] + +d = filter _, v in {a = "foo", b = "bar"} { + v == "foo" +} # {"a": "foo"} +``` + +Please pay attention to distinguish the difference between any expression and any type. When `any` is used in type annotations, it means that the value of the variable is arbitrary, while the any expression means that one of the elements in a set satisfies the condition. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/index.md new file mode 100644 index 000000000..c3ecc1626 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/index.md @@ -0,0 +1 @@ +# KCL 语言规范 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/kcl-spec.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/kcl-spec.md new file mode 100644 index 000000000..26e22eea7 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/kcl-spec.md @@ -0,0 +1,339 @@ +--- +title: "KCL Spec" +linkTitle: "KCL Spec" +type: "docs" +weight: 2 +description: KCL Spec +--- + +## Lexical rules + +### Keywords and reserved words + +The following are the keywords of the KCL: + +```python +True False None Undefined import +and or in is not +as if else elif for +schema mixin protocol check assert +all any map filter lambda +rule +``` + +The following are reserved words for the KCL: + +```python +pass return validate rule flow +def del raise except try +finally while from with yield +global nonlocal struct class final +``` + +### Line comment + +```python +# a comment +``` + +### Operators + +```python ++ - * ** / // % +<< >> & | ^ < > +~ <= >= == != = ++= -= *= **= /= //= %= +<<= >>= &= ^= +``` + +### Delimiters + +```python +( ) [ ] { } +, : . ; @ +``` + +### Operator precedence + +The following list of operators is ordered from **highest to lowest**: + +| Operator | Description | +| -------------------------------------------------------------------------------- | -------------------------------------------------------- | +| `**` | Exponentiation (highest priority) | +| `+x` `-x` `~x` | Positive, negative, bitwise NOT | +| `*` `/` `%` `//` | Multiplication, division, floor division and remainder | +| `+` `-` | Addition and subtraction | +| `<<` `>>` | Left and right shifts | +| `&` | Bitwise AND | +| `^` | Bitwise XOR | +| \| | Bitwise OR | +| `in`, `not in`, `is`, `is not`, `<`, `<=`, `>`, `>=`, `!=`, `==` | Comparisons, including membership and identity operators | +| `not` | Boolean NOT | +| `and` | Boolean AND | +| `or` | Boolean OR | +| `if – else` | Conditional expression = | +| `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `&=`, `=`, `^=`, `\*\*=`, `//=`, `<<=`, `>>=` | Assign | + +## Grammar + +KCL uses Python's [LarkParser](https://lark-parser.readthedocs.io/en/latest/) tool to describe the grammar, and the specification rules are as follows: + +```bnf +//////////// KCL grammar //////////// +start: (NEWLINE | statement)* + +statement: simple_stmt | compound_stmt +simple_stmt: (assign_stmt | unification_stmt | expr_stmt | assert_stmt | import_stmt | type_alias_stmt) NEWLINE +compound_stmt: if_stmt | schema_stmt | rule_stmt + +//////////// import_stmt //////////// +import_stmt: IMPORT dot_name (AS NAME)? +dot_name: (leading_dots identifier) | identifier +leading_dots: DOT+ + +/////////// assert_stmt //////////// +assert_stmt: ASSERT simple_expr (IF simple_expr)? (COMMA test)? + +//////////// if_stmt //////////// +if_stmt: IF test COLON execution_block (ELIF test COLON execution_block)* (ELSE COLON execution_block)? +execution_block: if_simple_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT +if_simple_stmt: (assign_stmt | unification_stmt | expr_stmt | assert_stmt) NEWLINE + +//////////// assign_stmt //////////// +assign_stmt: identifier [COLON type] (ASSIGN identifier)* ASSIGN test + | identifier (COMP_PLUS | COMP_MINUS | COMP_MULTIPLY | COMP_DOUBLE_STAR | COMP_DIVIDE + | COMP_DOUBLE_DIVIDE | COMP_MOD | COMP_AND | COMP_OR | COMP_XOR | COMP_SHIFT_LEFT + | COMP_SHIFT_RIGHT) test + +//////////// unification_stmt //////////// +unification_stmt: identifier COLON schema_expr + +//////////// schema_stmt //////////// +schema_stmt: [decorators] (SCHEMA|MIXIN|PROTOCOL) NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [schema_body] +schema_arguments: schema_argument (COMMA schema_argument)* +schema_argument: NAME [COLON type] [ASSIGN test] +schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt|schema_init_stmt|schema_index_signature)* [check_block] _DEDENT +schema_attribute_stmt: attribute_stmt NEWLINE +attribute_stmt: [decorators] (identifier | STRING) [QUESTION] COLON type [(ASSIGN|COMP_OR) test] +schema_init_stmt: if_simple_stmt | if_stmt +schema_index_signature: LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS COLON type [ASSIGN test] NEWLINE + +//////////// rule_stmt //////////// +rule_stmt: [decorators] RULE NAME [LEFT_BRACKETS [schema_arguments] RIGHT_BRACKETS] [LEFT_PARENTHESES identifier (COMMA identifier)* RIGHT_PARENTHESES] [for_host] COLON NEWLINE [rule_body] +rule_body: _INDENT (string NEWLINE)* check_expr+ _DEDENT + +for_host: FOR identifier + +/////////// decorators //////////// +decorators: (AT decorator_expr NEWLINE)+ +decorator_expr: identifier [call_suffix] + +//////////// type //////////// +type: type_element (OR type_element)* +type_element: schema_type | function_type | basic_type | compound_type | literal_type +schema_type: identifier +function_type: LEFT_PARENTHESES [type_element (COMMA type_element)*] RIGHT_PARENTHESES [RIGHT_ARROW type_element] +basic_type: STRING_TYPE | INT_TYPE | FLOAT_TYPE | BOOL_TYPE | ANY_TYPE +compound_type: list_type | dict_type +list_type: LEFT_BRACKETS (type)? RIGHT_BRACKETS +dict_type: LEFT_BRACE (type)? COLON (type)? RIGHT_BRACE +literal_type: string | number | TRUE | FALSE + +//////////// type alias //////////// +type_alias_stmt: TYPE NAME ASSIGN type + +//////////// check_stmt //////////// +check_block: CHECK COLON NEWLINE _INDENT check_expr+ _DEDENT +check_expr: simple_expr [IF simple_expr] [COMMA primary_expr] NEWLINE + +//////////// mixin_stmt //////////// +mixin_stmt: MIXIN LEFT_BRACKETS [mixins | multiline_mixins] RIGHT_BRACKETS NEWLINE +multiline_mixins: NEWLINE _INDENT mixins NEWLINE _DEDENT +mixins: identifier (COMMA (NEWLINE mixins | identifier))* + + +//////////// expression_stmt //////////// +expr_stmt: testlist_expr +testlist_expr: test (COMMA test)* +test: if_expr | simple_expr +if_expr: simple_expr IF simple_expr ELSE test + +simple_expr: unary_expr | binary_expr | primary_expr + +unary_expr: un_op simple_expr +binary_expr: simple_expr bin_op simple_expr + +bin_op: L_OR | L_AND + | OR | XOR | AND + | SHIFT_LEFT | SHIFT_RIGHT + | PLUS | MINUS | MULTIPLY | DIVIDE | MOD | DOUBLE_DIVIDE + | DOUBLE_STAR + | EQUAL_TO | NOT_EQUAL_TO + | LESS_THAN | GREATER_THAN | LESS_THAN_OR_EQUAL_TO | GREATER_THAN_OR_EQUAL_TO + | IN | L_NOT IN | IS | IS L_NOT | L_NOT | AS +un_op: L_NOT | PLUS | MINUS | NOT + +primary_expr: identifier call_suffix | operand | primary_expr select_suffix | primary_expr call_suffix | primary_expr slice_suffix +operand: identifier | number | string | constant | quant_expr | list_expr | list_comp | config_expr | dict_comp | schema_expr | lambda_expr | LEFT_PARENTHESES test RIGHT_PARENTHESES +select_suffix: [QUESTION] DOT NAME +call_suffix: LEFT_PARENTHESES [arguments [COMMA]] RIGHT_PARENTHESES +slice_suffix: [QUESTION] LEFT_BRACKETS (test | [test] COLON [test] [COLON [test]]) RIGHT_BRACKETS +arguments: argument (COMMA argument)* +argument: test | NAME ASSIGN test | MULTIPLY test | DOUBLE_STAR test + + +//////////// operand //////////// +identifier: NAME (DOT NAME)* +quant_expr: quant_op [ identifier COMMA ] identifier IN quant_target LEFT_BRACE (simple_expr [IF simple_expr] | NEWLINE _INDENT simple_expr [IF simple_expr] NEWLINE _DEDENT)? RIGHT_BRACE +quant_target: string | identifier | list_expr | list_comp | config_expr | dict_comp +quant_op: ALL | ANY | FILTER | MAP +list_expr: LEFT_BRACKETS [list_items | NEWLINE [list_items]] RIGHT_BRACKETS +list_items: list_item ((COMMA [NEWLINE] | [NEWLINE]) list_item)* [COMMA] [NEWLINE] +list_item: test | star_expr | if_item +list_comp: LEFT_BRACKETS (list_item comp_clause+ | NEWLINE list_item comp_clause) RIGHT_BRACKETS +dict_comp: LEFT_BRACE (entry comp_clause+ | NEWLINE entry comp_clause+) RIGHT_BRACE +entry: test (COLON | ASSIGN | COMP_PLUS) test +comp_clause: FOR loop_variables [COMMA] IN simple_expr [NEWLINE] [IF test [NEWLINE]] +if_entry: IF test COLON if_entry_exec_block (ELIF test COLON if_entry_exec_block)* (ELSE COLON if_entry_exec_block)? +if_entry_exec_block: (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) [NEWLINE] | NEWLINE _INDENT (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry) ((COMMA [NEWLINE] | [NEWLINE]) (test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry))* [COMMA] [NEWLINE] _DEDENT +if_item: IF test COLON if_item_exec_block (ELIF test COLON if_item_exec_block)* (ELSE COLON if_item_exec_block)? +if_item_exec_block: list_item [NEWLINE] | NEWLINE _INDENT list_item ((COMMA [NEWLINE] | NEWLINE) list_item)* [COMMA] [NEWLINE] _DEDENT + +star_expr: MULTIPLY test +double_star_expr: DOUBLE_STAR test +loop_variables: primary_expr (COMMA primary_expr)* +schema_expr: identifier (LEFT_PARENTHESES [arguments] RIGHT_PARENTHESES)? config_expr +config_expr: LEFT_BRACE [config_entries | NEWLINE [config_entries]] RIGHT_BRACE +config_entries: config_entry ((COMMA [NEWLINE] | [NEWLINE]) config_entry)* [COMMA] [NEWLINE] +config_entry: test (COLON | ASSIGN | COMP_PLUS) test | double_star_expr | if_entry + +//////////// lambda_expr //////////// +lambda_expr: LAMBDA [schema_arguments] [RIGHT_ARROW type] LEFT_BRACE [expr_stmt | NEWLINE _INDENT schema_init_stmt+ _DEDENT] RIGHT_BRACE + +//////////// misc //////////// +number: DEC_NUMBER [multiplier] | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER +multiplier: SI_N_L | SI_U_L | SI_M_L | SI_K_L | SI_K | SI_M | SI_G | SI_T | SI_P + | SI_K_IEC | SI_M_IEC | SI_G_IEC | SI_T_IEC | SI_P_IEC +string: STRING | LONG_STRING +constant : TRUE | FALSE | NONE | UNDEFINED + +// Tokens +ASSIGN: "=" +COLON: ":" +SEMI_COLON: ";" +COMMA: "," +QUESTION: "?" +ELLIPSIS: "..." +RIGHT_ARROW: "->" +LEFT_PARENTHESES: "(" +RIGHT_PARENTHESES: ")" +LEFT_BRACKETS: "[" +RIGHT_BRACKETS: "]" +LEFT_BRACE: "{" +RIGHT_BRACE: "}" +PLUS: "+" +MINUS: "-" +MULTIPLY: "*" +DIVIDE: "/" +MOD: "%" +DOT: "." +AND: "&" +OR: "|" +XOR: "^" +NOT: "~" +LESS_THAN: "<" +GREATER_THAN: ">" +EQUAL_TO: "==" +NOT_EQUAL_TO: "!=" +GREATER_THAN_OR_EQUAL_TO: ">=" +LESS_THAN_OR_EQUAL_TO: "<=" +DOUBLE_STAR: "**" +DOUBLE_DIVIDE: "//" +SHIFT_LEFT: "<<" +SHIFT_RIGHT: ">>" +AT: "@" + +COMP_PLUS: "+=" +COMP_MINUS: "-=" +COMP_MULTIPLY: "*=" +COMP_DIVIDE: "/=" +COMP_MOD: "%=" +COMP_AND: "&=" +COMP_OR: "|=" +COMP_XOR: "^=" +COMP_DOUBLE_STAR: "**=" +COMP_DOUBLE_DIVIDE: "//=" +COMP_SHIFT_LEFT: "<<=" +COMP_SHIFT_RIGHT: ">>=" + +// Special tokens +IMPORT: "import" +AS: "as" +RULE: "rule" +SCHEMA: "schema" +MIXIN: "mixin" +PROTOCOL: "protocol" +CHECK: "check" +FOR: "for" +ASSERT: "assert" +IF: "if" +ELIF: "elif" +ELSE: "else" +L_OR: "or" +L_AND: "and" +L_NOT: "not" +IN: "in" +IS: "is" +LAMBDA: "lambda" +ALL: "all" +ANY: "any" +FILTER: "filter" +MAP: "map" +TYPE: "type" + +ANY_TYPE: "any" +STRING_TYPE: "str" +INT_TYPE: "int" +FLOAT_TYPE: "float" +BOOL_TYPE: "bool" + +// Constant tokens +TRUE: "True" +FALSE: "False" +NONE: "None" +UNDEFINED: "Undefined" + +// Binary prefix +SI_N_L: "n" +SI_U_L: "u" +SI_M_L: "m" +SI_K_L: "k" +SI_K: "K" +SI_M: "M" +SI_G: "G" +SI_T: "T" +SI_P: "P" +SI_K_IEC: "Ki" +SI_M_IEC: "Mi" +SI_G_IEC: "Gi" +SI_T_IEC: "Ti" +SI_P_IEC: "Pi" +IEC: "i" + +NAME: /\$?[a-zA-Z_]\w*/ +COMMENT: /#[^\n]*/ +NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ + +STRING: /r?("(?!"").*?(? **note** +> +> Any character except the ASCII space, tab (`\t`) and formfeed (`\f`) is considered a none-space character. + +- A line ending in a backslash cannot carry a comment (, which will be introduced shortly afterwards). +- A backslash does not continue a comment. +- A backslash does not continue a token except for string literals (i.e., tokens other than string literals cannot be split across physical lines using a backslash). +- A backslash is illegal elsewhere on a line outside a string literal. + +### Implicit Line Joining + +Expressions in parentheses, square brackets or curly braces can be split over more than one physical line without using backslashes. + +- Implicitly continued lines can carry comments. +- The indentation of the continuation lines is not important. +- Blank continuation lines are allowed. +- There is no `NEWLINE` token between implicit continuation lines. +- Implicitly continued lines can also occur within triple-quoted strings (see below); in that case they cannot carry comments. + +### Blank Lines + +### Indentation + +### Comments + +Starting with a `#` character that is not part of a string literal is a comment. A comment ends at the end of the physical line. + +A comment signifies the end of the logical line unless the implicit line joining rules are invoked. + +Comments are ignored by the syntax. + +### Identifiers and Keywords + +Identifiers (also referred to as names) are described by the following lexical definitions. + +Within the ASCII range (from `U+0001` to `U+007F`), the valid characters for identifiers are the uppercase and lowercase letters `A` through `Z`, the underscore `_` and, except for the first character, the digits `0` through `9`. + +Identifiers are unlimited in length. The case is significant. + +### Keywords + +The following identifiers are used as reserved words, or keywords of the language, and cannot be used as ordinary identifiers. They must be spelled exactly as written here: + +```python +True False None Undefined import +and or in is not +as if else elif for +schema mixin protocol check assert +all any map filter lambda +rule +``` + +The following tokens are not used, but they are reserved as possible future keywords: + +```python +pass return validate rule flow +def del raise except try +finally while from with yield +global nonlocal struct class final +``` + +### Literals + +Literals are notations for constant values of some built-in types. + +### String Literals + +String literals are described by the following lexical definitions: + +``` +stringliteral ::= [stringprefix](shortstring | longstring) +stringprefix ::= "r" | "R" +shortstring ::= "'" shortstringitem* "'" | '"' shortstringitem* '"' +longstring ::= "'''" longstringitem* "'''" | '"""' longstringitem* '"""' +shortstringitem ::= shortstringchar | stringescapeseq +longstringitem ::= longstringchar | stringescapeseq +shortstringchar ::= +longstringchar ::= +stringescapeseq ::= "\" +``` + +Multiple adjacent string or bytes literals (delimited by whitespace),possibly using different quoting conventions, are allowed, and their meaning is the same as their concatenation. + +### Numeric Literals + +There are two types of numeric literals: integers and floating-point numbers. + +Integer literals are described by the following lexical definitions: + +``` +integer ::= decinteger | bininteger | octinteger | hexinteger +decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")* +bininteger ::= "0" ("b" | "B") (["_"] bindigit)+ +octinteger ::= "0" ("o" | "O") (["_"] octdigit)+ +hexinteger ::= "0" ("x" | "X") (["_"] hexdigit)+ +nonzerodigit ::= "1"..."9" +digit ::= "0"..."9" +bindigit ::= "0" | "1" +octdigit ::= "0"..."7" +hexdigit ::= digit | "a"..."f" | "A"..."F" +``` + +Floating-point literals are described by the following lexical definitions: + +``` +floatnumber ::= pointfloat | exponentfloat +pointfloat ::= [digitpart] fraction | digitpart "." +exponentfloat ::= (digitpart | pointfloat) exponent +digitpart ::= digit (["_"] digit)* +fraction ::= "." digitpart +exponent ::= ("e" | "E") ["+" | "-"] digitpart +``` + +## Operators and Delimiters + +### Operators + +The following tokens are operators: + +```python ++ - * ** / // % +<< >> & | ^ < > +~ <= >= == != @ +``` + +### Delimiters + +The following tokens serve as delimiters in the grammar: + +```python +( ) [ ] { } +, : . ; = += +-= *= **= /= //= %= +<<= >>= &= |= ^= +``` + +The period can also occur in floating-point literals. + +The following printing ASCII characters have special meaning as part of other tokens or are otherwise significant to the lexical analyzer: + +``` +' " # \ +``` + +The following printing ASCII characters are not used in KCL. Their occurrence outside string literals and comments is an unconditional error: + +``` +? ` +``` + +## Reference + +Since the lexical conventions of KCL is very similar to that of Python, we use the following document as the reference when writing this chapter. + +- [https://docs.python.org/3/reference/lexical_analysis.html](https://docs.python.org/3/reference/lexical_analysis.html) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/modules.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/modules.md new file mode 100644 index 000000000..2f54a281d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/modules.md @@ -0,0 +1,350 @@ +--- +title: "Modules" +linkTitle: "Modules" +type: "docs" +weight: 2 +description: Modules +--- + +## Modules and the Import System + +KCL code is organized in **modules**. For code in one module to access the code defined in another module, a process called **importing** must be used. + +Importing is undertaken at compile-time in KCL. The advantage is to have static checking enabled. + +A regular KCL module is a file on the file system. It is required to have a `.k` suffix. + +## Packages + +To help manage modules and provide a naming hierarchy, KCL has the concept of packages. In KCL, a package maps to exactly a file system directory, and a regular module maps to a file. + +Files directly under a package are considered parts of the package, instead of individual regular modules. + +Packages can have sub-packages. + +Packages are special modules: + +- All packages in KCL are modules. +- A single-file module can never be a package. + +All modules have a name. + +Sub package names are separated from their parent package name by dots. + +To summary, a regular KCL module is a `.k` file, and a package is a directory on the file system. All `.k` files directly under the directory are included in the package, other files are ignored. If the directory has subdirectories, they become sub-packages as long as there are `.k` files underneath. + +### Intra-Package Name Space Sharing + +Inside a package, all `.k` files are considered parts of the package, instead of regular modules. Code in these files share a single name space and can access names defined in other files, without explicitly granted. + +### Package Initialization + +A package can have the initialization code. The code must exist in only one of the `.k` files under this package. The interpreter guarantees that the initialization code is executed after all definitions. + +## Searching + +The searching begins when an `import` statement is used to import a module. + +### Module Cache + +In KCL, only standard system modules are cached. When a cached module is imported, the cached version is used. In other words, KCL runtime would not create another copy of the standard system module in memory. + +However, other modules are uncached. Importing a module multiple time would create multiple instances of the module. + +### Module Names + +An `import` statement specifies the name of the module to import. The syntax is: + +``` +import [as ] +``` + +The rule to search with the module name is very simple: + +- **Step 1**: Searches the module name from the **standard system modules**, then **plugins modules**. + - See **standard system modules** and **plugins modules** for more details. If matched, the module is imported. Otherwise, continue to **Step 2**. +- **Step 2**. Whether a module name starts with a `.` is checked. If yes, the name is a so-called relative pathname, and we go to **Step 5**. Otherwise, continue to **Step 3**. +- **Step 3**: If the module name does not start with any `.`, then the compiler searches the nearest `root path` directory from this directory to the parent, and find the module according to the name just from the `root path`. If no `root path` is found, find the module according to the name from the folder the `.k` file including this `import` statement exists. + - **root path**: the directory contains a `kcl.mod` file. If matched, the module is imported. Otherwise, continue to **Step 4**. +- **Step 4**: Then the compiler checks if the name is the name of any library module that requires explicit loading. If matched, the library module is imported. Otherwise, continue to **Step 6**. +- **Step 5**. For relative importing, find the module according to the name from the folder the `.k` file including this `import` statement exists. Interpret leading dots using the following rule: +- One dot: Ignore. +- Tow or more dots: Suppose there are `n` leading dots, then the searching starts at `n - 1` levels above this folder. If matched, the module is imported. Otherwise, continue to **Step 6**. +- **Step 6**. Module not found, report an error. + +Do case-sensitive search when the operating system allows. If case-sensitive search is not allowed, search directories before regular files. + +In KCL, the `from <> import <>` is unsupported, and relative import is performed with the `import <>` syntax. + +### Uniqueness of Module + +Each module has a unique location path in its scope, so that a module or package could be located with a unique location path, such as `a.b.c`. + +Searching by location path should be supported by the kcl compiler, which needs to provide corresponding searching features through the command line and api form. + +## Standard System Packages + +KCL supports a few standard system modules. [Here](docs/reference/model/overview) is the full list of these standard system modules. + +### The Built-in System Package + +KCL provides a list of built-in system modules, which are loaded automatically and can be directly used without providing any module name. For example, `print` is a widely used built-in module. + +The following is the full list of these built-in system modules: + +- print() + - The print function. +- multiplyof(a, b) + - Check if the modular result of a and b is 0 +- isunique(inval) + - Check if a list has duplicated elements +- len(inval) + Return the length of a value +- abs(x) + Return the absolute value of the argument. +- all(iterable) + Return True if bool(x) is True for all values x in the iterable. If the iterable is empty, return True. +- any(iterable) + Return True if bool(x) is True for any x in the iterable. If the iterable is empty, return False. +- bin(number) + Return the binary representation of an integer. +- hex(number) + Return the hexadecimal representation of an integer. +- oct(number) + Return the octal representation of an integer. +- ord(c) -> int + Return the Unicode code point for a one-character string. +- sorted(iterable) + Return a new list containing all items from the iterable in ascending order. A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order. +- range(start, end, step=1) + Return the range of a value with start, end and step parameter. +- min(iterable) + With a single iterable argument, return its smallest item. The default keyword-only argument specifies an object to return if the provided iterable is empty. With two or more arguments, return the smallest argument. +- max(iterable) + With a single iterable argument, return its biggest item. The default keyword-only argument specifies an object to return if the provided iterable is empty. With two or more arguments, return the largest argument. +- sum(iterable, start) + Return the sum of a 'start' value (default: 0) plus an iterable of numbers. When the iterable is empty, return the start value. This function is intended specifically for use with numeric values and may reject non-numeric types. +- pow(x, y, z) + Equivalent to `x**y` (with two arguments) or `x**y % z` (with three arguments). Some types, such as ints, are able to use a more efficient algorithm when invoked using the three argument form. +- round(number, ndigits) + Round a number to a given precision in decimal digits. The return value is an integer if ndigits is omitted or None. Otherwise the return value has the same type as the number. ndigits may be negative. +- typeof(x: any, \*, full_name: bool = False) -> str + Return the type of the value 'x' at runtime. When the 'full_name' is 'True', return the full package type name such as `pkg.schema`. + +### Plugin Modules + +KCL compiler needs to provide the ability to dynamically expand and load plugin modules without modifying the compiler itself. KCL compiler needs to support flexible pluggable module extension mechanism, so that KCL users can use more abundant built-in function capabilities to simplify writing. + +KCL compiler needs to ensure the stability and safety of the expansion mechanism, without affecting the core of the compiler. + +Searching extended plugin module is performed after the standard system module. The standard system module has a higher priority in naming. If it exists a standard or built-in system module with the same name, the extended plugin module will be ignored. + +Importing and using the extended plugin module should be consistent with the standard or built-in system module. + +### Replacing Standard System Packages + +Replacing standard system modules is not allowed. + +## Examples + +We show more module features through an example. + +Suppose we have the following directories and files: + +``` + . + ├── mod1.k + ├── mod2.k + ├── pkg1 + │   ├── def1.k + │   ├── def2.k + │   └── def3init.k + └── pkg2 + ├── file2.k + └── subpkg3 + └── file3.k +``` + +From the structure we can see that `pkg1` and `pkg2` are two packages, `subpkg3` is a subpackage of `pkg2`, and `mod1.k` and `mod2.k` are regular modules. + +### Importing a Standard System Package + +The following statement can import the standard system module `math` + +```python +import math +``` + +This is the only way to import a standard system module. After importing a standard system module, functions, variables and schemas defined in it can be used. For example, the following statement uses the `log10` function +defined in `math` + +```python +a = math.log10(100) # a is 2 after computation. +``` + +### Importing a Regular Module + +In `mod1.k`, we can import `mod2` using one of the following syntaxes. + +```python +import mod2 +``` + +```python +import .mod2 +``` + +The difference is that in the first syntax, the KCL compiler will first try to check if `mod2` matches any of the standard system modules' name. Since it does not match any standard system module's name, the statement will check the directory where `mod1.k` resists in, like what the second statement does. + +Suppose in `mod2.k` there is a definition of a variable:: + +```python +a = 100 +``` + +After importing `mod2`, we can access `a` in `mod1.k` using the following syntax + +```python +b = mod2.a +``` + +### Importing a Package + +In `mod1.k`, we can import `pkg1` using one of the following syntaxes. + +```python +import pkg1 +``` + +```python +import .pkg1 +``` + +The difference is that in the first syntax, the KCL compiler will first try to check if `pkg1` matches any of the standard system modules' name. Since it does not match any standard system module's name, the statement will check the directory where `mod1.k` resists in, like what the second statement does. + +We can use similar statements to import `pkg2`. Note that importing `pkg2` will not import `subpkg3`. + +The name of the package is the name of the imported module. + +Suppose in `file2.k` that is inside `pkg2` there is a definition to variable `foo` + +```python +foo = 100 +``` + +This variable can be used in `mod1.k` after importing `pkg2` like the following + +```python +bar = pkg2.foo +``` + +### Importing a Subpackage + +To import `subpkg3` from `mod1.k`, one of the following statements can be used. + +```python +import pkg2.subpkg3 +``` + +```python +import .pkg2.subpkg3 +``` + +The behaviors of these statements are identical. + +The name of the subpackage is the name of the imported module. + +Suppose in `file3.k` that is inside `subpkg3` there is a definition to variable `foo` + +```python +foo = 100 +``` + +This variable can be used in `mod1.k` after importing `subpkg3` like the following + +```python +bar = subpkg3.foo +``` + +### Relative Importing + +Relative importing is useful when there is code trying to import modules that does not exist recursively inside the current directory. + +For example, the following statements, if written in `file3.k`, can be used to import `pkg2`, `pkg1` and `mod2` respectively. + +```python +import ...pkg2 # Go two levels up then import pkg2 +import ...pkg1 # Go two levels up then import pkg1 +import ...mod2 # Go two levels up then import mod2 +``` + +### Importing from a Root Path + +Suppose we have a `kcl.mod` file in the directory to mark it as a root path, then we have the following files: + +``` + . + |── kcl.mod + ├── mod1.k + ├── mod2.k + ├── pkg1 + │   ├── def1.k + │   ├── def2.k + │   └── def3init.k + └── pkg2 + ├── file2.k + └── subpkg3 + └── file3.k +``` + +In `pkg1` `def1.k`, we can import `pkg2.subpkg3` `file3` using the following syntaxes. + +```python +import pkg2.subpkg3.file3 +``` + +Importing from the root path is very convenient when the code is trying to import modules from a directory needs to look up multiple directories above this directory. At also, it is helpful to organize a large number of files in a root directory. + +### Importing a Module Inside a Package + +Note that `subpkg3` is only implemented with one file `file3.k`. The file can be regarded as a regular module and imported directly. + +In `mod1.k`, the importing statement would be:: + +```python +import pkg2.subpkg3.file3 +``` + +Different from importing `subpkg3`, now the name of the module is `file3`. We can access the variable `foo` defined in this module with the following +statement + +```python +bar = file3.foo +``` + +### Precedence of Importing + +When an import statement specifies a package to import, the virtual machine first looks for a directory named according to the import statement in the file system. + +If such a directory is not found, the virtual machine looks for a single file module. + +For example, when the statement `import a.b.c` appears, the virtual machine first looks for the directory `a/b/c` from the directory of the current file. If `a/b/c` is not found, the virtual machine looks for a file named `a/b/c.k`. If the file is also absent, an error is reported. + +### Package Implemented with Multiple Files + +Package `pkg1` is implemented with multiple KCL files. + +Multiple files can be used to define variables, schemas and functions, and they can access names defined in other files of this package. + +For example, suppose `def1.k` defines a variable `foo`, `def2.k` defines `bar`, and `def3init.k` defines a variable `baz`, when `pkg1` is imported by `mod1.k`, all these variable can be used + +```python +import pkg1 +a = pkg1.foo + pkg1.bar + pkg1.baz +``` + +Inside a module, names defined in a file can be accessed in another file without further importing. For example, suppose `bar` in `def2.k` would invoke `foo` defined in `def1.k`, it can directly use `foo` like the following + +```python +bar = foo + 1 +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/schema.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/schema.md new file mode 100644 index 000000000..545f2e6bf --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/schema.md @@ -0,0 +1,916 @@ +--- +title: "Schema" +linkTitle: "Schema" +type: "docs" +weight: 2 +description: Schema +--- + +## Syntax + +### Schema Definition + +A schema is a language element to define a type of configuration data. + +To define a schema, the syntax is the following: + +```bnf +schema_stmt: [decorators] "schema" identifier ["[" [arguments] "]"] ["(" operand_name ")"] ":" NEWLINE [schema_body] +schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt | schema_index_signature | statement)* [check_block] _DEDENT +``` + +Attributes could be defined in a schema, the syntax is the following: + +```bnf +schema_attribute_stmt: [decorators] identifier ["?"] ":" type [(ASSIGN | augassign) test] NEWLINE +``` + +Index signature could be defined in a schema, the syntax is the following: + +```bnf +schema_index_signature: LEFT_BRACKETS [NAME COLON] [ELLIPSIS] basic_type RIGHT_BRACKETS COLON type [ASSIGN test] NEWLINE +``` + +Once defined, an attribute must have a valid type: + +```bnf +type: type_element ("|" type_element)* +type_element: schema_type | basic_type | list_type | dict_type +schema_type: operand_name +basic_type: "str" | "int" | "float" | "bool" +list_type: "[" (type)? "]" +dict_type: "{" (type)? COLON (type)? "}" +``` + +The followings are some basic examples: + +```python +# A person has a first name, a last name and an age. +schema person: + firstName: str + lastName: str + # fullName is generated by firstName and lastName + fullName: str = firstName + ' ' + lastName + # The default value of age is 0 + age: int = 0 + +# An employee IS a person, and has some additional information. +schema employee(person): + bankCard: int + nationality: str + +# A company has a name and many employees. +schema company: + name: str + employees: [employee] +``` + +More complex schema definitions will be elaborated after other concepts are +introduced. + +#### Optional Attribute + +Each attribute **must** be assigned with a not-None value as a schema instance unless it is modified by a question mark as an optional attribute. + +Examples: + +```bnf +schema employee(person): + bankCard?: int # bankCard is an optional attribute + nationality?: str # # nationality is an optional attribute +``` + +When there is an inheritance relationship: + +- If the attribute is optional in the base schema, it could be optional or required in the sub-schema. +- If the attribute is required in the base schema, it must be required in the sub-schema. + +### Configuration Definition + +A configuration is structured data stored in a dict-like structure. In KCL, we have introduced +the configuration definition syntax as a variant of dict definition syntax. + +```bnf +schema_expr: operand_name ("(" [arguments] ")")? dict_expr +``` + +As can be seen, apart from having an identifier as schema type, a configuration definition +is just an ordinary dict definition, and each key in the dict matches an attribute in the schema. + +To simplify configuration, schema attribute key is much easier to define as: + +- schema attribute key can be unquoted. When the attribute key has the same name as a variable, it must be quoted as a normal dict to avoid naming conflict. +- schema attribute key can be defined nested through `select expression`, such as `a.b.c`. + +The comma at the end of each line can be omitted. + +For example, we can define a `person` named `John Doe` using the following statement: + +```python +johnDoe = person { + # In the result, 'lastName' appears later than 'firstName', according the schema + lastName = 'Doe' + firstName = 'John' + # If we don't specify the 'age', the default value 0 is used. + # 'age': 20 +} +``` + +The result is a **dict**: + +```python +{ + 'firstName': 'John' + 'lastName': 'Doe' + 'age': 0 +} +``` + +Compared to the ordinary dict definition, a configuration definition has the following features: + +- Each attribute defined in the schema (or one of the schemas) could be configured, and config data has higher priority than the default value. +- When an attribute defined in the schema (or one of the schemas) is not configured in the configuration definition statement, and it has a default value, the default value is used. +- Unless the schema (or one of the schemas) is a **relaxed schema**, no more attributes can be defined. +- The quotation marks of dict key can be omitted. +- The comma at the end of each line can be omitted. +- Cases of **inheritance** will be discussed separately. + +For attributes of list, dict and schema types, the config data is added by **union** instead of reassignment. For instance: + +```python +schema Name: + firstName: str + lastName: str + +schema Person: + name: Name = { + firstName = "John" + lastName = "default" + } + +JohnDoe = Person { + name.lastName = "Doe" +} +``` + +The result is a **dict**: + +```python +{ + 'firstName': 'John' + 'lastName': 'Doe' +} +``` + +#### Attribute Identify + +Each key identifier in the configuration expr identifies an element or a range of elements in a schema. The key identifier may consist of multiple attribute identifiers, and each attribute may be a basic type value, a list, a dict or schema. For example, the key identifier 'a.b.c' identifies the element 'c' in the 'A' schema: + +```python + +schema C: + c: int + +schema B: + b: C + +schema A: + a: B + +A { + a.b.c: 5 +} +``` + +To make the key identifier usage rules as clear as possible, we define the way of identifying with complex data types as follows. + +##### List + +Suppose we have a list attribute a. + +Identify an element in a: + +```python +a[0] # the first element +a[3] # the 4th element +a[-1] # the last element +a[-2] # the penultimate element +``` + +Identify a range of elements in the list: + +```python +a[2:5] # a slice of the third, 4th, and 5th elements +a[:5] # a slice of the first to 5th elements +``` + +#### Attribute Operator + +Once we identified the element(s), we can declare operation on it. It follows the pattern of `identifier op E`. + +#### Union + +Pattern: `identifier : E` + +The value of the expression `E` will be unioned into the element value. + +Examples: + +```python +a = A { + # union {d:4} into the element b.c, suppose c is a schema with an int type attribute d. + b.c : { + d : 4 + } +} +``` + +See 'union' in `expressions` spec for more details. + +#### Override + +Pattern: `identifier = E` + +The value of the expression `E` will override the element value. + +Examples: + +```python +a = A { + # override {c:4} to the element b, suppose b is a schema with an int type attribute c. + b = { + c: 4 + } +} +``` + +Unlike union, the override operation will reassign the element with a brand new value. +For basic type value, `union` and `override` have equivalent effects. + +Note: + +- Especially, we can "delete" its content by overriding the element to `Undefined`, such as `{ a = Undefined }`. + +#### Insert + +Pattern: `identifier += E` +Insert only works for list type `identifier`. + +List `E` will be inserted just after the specified index of the list `identifier`, and the following elements after the index will be automatically shifted. + +Examples: + +```python +a = A { + # insert {c:4} to the end position(just after index=1), suppose b is a list of schema with an int type attribute c. + b += { + c: 4 + } +} +``` + +If no index is specified, the last index will be used. + +The type of 'E' must be compatible with the type of list. See `types` for more details. + +#### Index Signature + +Index signatures can be defined in the KCL schema, and it means that the key-value constraints of the index signature can be used to construct a dict with the schema type, or additional checks can be added to the relaxed schema attributes to enhance the KCL type and semantic checks. + +- Use the form `[{attr_alias}: {key_type}]: {value_type}` to define an index signature in the schema, and `{attr_alias}` can be omitted. + +```python +schema Map: + """ + Map is a relaxed schema with a key of str type and a value of str type + """ + [str]: str # `{attr_alias}` can be omitted. + +data = Map { + key1 = "value1" + key2 = "value2" +} +``` + +- Mandatory all attributes of the schema key and value types + +```python +schema Person: + name: str + age: int # error, conflicts with the index signature definition `[str]: str` + [str]: str # The values of all attributes of the schema can only be strings +``` + +- Mandatory all attribute key and value types are defined in the schema, which is equivalent to restricting all attribute types except the relaxed attributes. + +```python +schema Person: + name: str + age: int + [...str]: str # Except for the `name` and `age` attributes, the key type of all other attributes of the schema must be `str`, and the value type must also be `str`. +``` + +- Define the index signature attribute alias and use it with the check block. + +```python +schema Data: + [dataName: str]: str + check: + dataName in ["Alice", "Bob", "John"] + +data = Data { + Alice = "10" + Bob = "12" + Jonn = "8" # error Jonn not in ["Alice", "Bob", "John"] +} +``` + +```python +import regex + +schema DataMap: + [attr: str]: str + check: + regex.match(attr, r'^[-_a-zA-Z0-9]+$') + +data = DataMap { + key1 = "value1" + "foo.bar" = "value2" # check error +} +``` + +### Schema Context + +The schema definition space can be regarded as a separate function context. + +Init statement could be defined inside the schema, the syntax is the following: + +```bnf +statement: small_stmt NEWLINE | if_stmt +``` + +The following is an example: + +```python +schema Person: + firstName: str = "John" + lastName: str + # fullName is generated by firstName and lastName in a separate init statement + fullName: str = firstName + ' ' + lastName + +JohnDoe = Person { + lastName = "Doe" +} +``` + +The result is a **dict**: + +```python +{ + 'firstName': 'John' + 'lastName': 'Doe' + 'fullName': 'John Doe' +} +``` + +If statement, expr statement and assert statement are supported as a schema init +statement. See more in statement spec. + +- The attributes must be defined first, including inherited ones, and then used in the init statement. +- Statements in the schema context will be executed sequentially. +- The value of attributes referenced in the init statement will be evaluated at runtime. + See the **Configuration Definition** section for the assignment rules of non-referenced attributes. For example, `"fullName"` in Person is generated by `"firstName"` and `"lastName"` evaluated at runtime, in which firstName is 'John', and lastName is "Doe". + +The immutability of attributes in the schema context follows the same rules as the immutability of global variables: + +```python +schema Person: + age: int = 1 # Immutable attribute + _name: str = "Alice" # Mutable attribute + + age = 10 # Error + _name = "Bob" # Ok +``` + +#### Arguments + +Schema context can also have arguments. The following is an example. + +```python +schema Person[separator]: + firstName: str = "John" + lastName: str + fullName: str = firstName + separator + lastName + +JohnDoe = Person('_') { + lastName = "Doe" +} +``` + +The example is similar to the previous one, except that the separator character used in +the `"fullName"` member is passed in as an argument. The way to perform a schema generation +when the schema has an initialization function with arguments is demonstrated in the code. + +### Check Block + +Optionally, a check block can be added to a schema definition to allow +additional checking to be performed. + +The syntax is the following: + +```bnf +check_block: "check" ":" NEWLINE _INDENT check_expr+ _DEDENT +check_expr: test (IF test)? [":" primary_expr] NEWLINE +``` + +In terms of grammatical definition, a check block consists of a list of conditional expressions. The following is an example: + +```python +schema employee(person): + bankCard: int + gender: str + + check: + len(str(bankCard)) == 16 + gender in ['male', 'female'], "The gender {} is unsupported".format(gender) +``` + +The ability of KCL check expressions covers the abilities that can be defined by OpenAPI spec and is aligned with the ability of logical expressions. We consider further aligning the syntax with `CEL` spec. +Whether to support `lambda expressions` is still under discussion. + +Summary: + +- A check block consists of one or more logical **expressions**. +- When defining a configuration, the expressions in the check block are evaluated + in any order. If any of the expression is `False`, an error is reported. +- A custom error message can be provided after an expression. + +### Specifying Types + +Optionally, the type of any member of a schema can be specified. As previous examples have shown. + +A member can be of a basic type, such as a string (`str`), a floating-point number (`float`), a fixed-point number (`int`) or a boolean number (`bool`). + +A member can also be of a dictionary generated from another schema. In such a case, the name of the other schema is used as the type name. + +A member can also be a list or an ordinary dict: + +- A list with unspecified type of elements is `[]`. +- A list with elements of type `t` is `[t]`. Here `t` is another type. +- A dict with keys of type `kt` and values of type `vt` is `{kt:vt}`. +- `kt`, `vt` or both of them can be missing, like a list with unspecified type of elements. + +The followings are some more examples: + +- A list of lists of strings: `[[str]]`. +- A dict of keys with the type string and unspecified value types: `{str:}`. + +A member can be a **union type** defined by `|`, such as `a | b`, which means the type of the member could be a or b. + +A union type can include types of `int`, `str`, `float`, `bool`, `list` and `dict` and support type nesting e.g. `{str:str|int}` and `[[int|str]|str|float]`, etc. + +Examples: + +```python +schema x: + p: int | str # p could be defined as a int or string +``` + +### Immutability + +KCL pursues strict immutability of schema attributes. It's generally followed the rules: + +- For the attributes of the basic type, such as string, int and float, it's allowed to be reassigned + through the init statement in **schema context** or by the **configuration definition**. +- For the attributes of list, dict and schema type, it's allowed to be reassigned only by the init statement in **schema context**. The content of it is allowed to be operated in **schema context** or by the **configuration definition**. +- Any other attempt to reassign or modify schema attribute will report an error. + +#### Assign by Value + +When using a schema variable to assign the value to another variable, we can only get a deep copy of its value, not a pointer or reference. That is, modifying the assigned value will not change the assigned schema variable. + +```python +schema Person: + name: str + +person = { + name = "Alice" +} +personCopy = person # 'personCopy' is a deep copy of 'person' and modifying 'personCopy' will not affect 'person' +``` + +### Union Operator + +For list, dict and schema, we can union delta to existing data. For example: + +```python +schema Name: + firstName: str + lastName: str + +schema Person: + name: Name = { + firstName = "John" + } + + # union a schema and a dict + name: Name { + lastName = "Doe" + } + +person = Person {} +``` + +The result is a **dict**: + +```python +{ + 'person': { + 'name': { + 'firstName': 'Jhon', + 'lastName': 'Doe' + } + } +} +``` + +### Other Operators + +Except for `assignment` and `union assignment`, it's not support other operators on schema type data. +Report an error if trying to use other operators on schema type data. + +### Deprecated + +The schema attribute can be marked as deprecated once it's considered invalid. + +```python +schema Person: + @deprecated(version="1.1.0", reason="use fullName instead", strict=True) + name: str + ... # Omitted contents + +person = Person { + # report an error on configing a deprecated attribute + name = "name" +} +``` + +- Deprecated attributes cannot be configured under any circumstances. Report an error or warning once the attribute is assigned. +- Define the expired version of the attribute through **version**, and define the reason for the attribute expired through **reason**. +- When strict is true, the attribute assignment will cause an error, otherwise it will report a warning and ignore the attribute assignment. + +### Composition + +The composition is a common way to define complex structures. KCL provides simplified means for the configuration definition of combined structures. + +Assuming we have the following schemas, which is defined by a combination of multiple schemas. + +```python +schema Name: + firstName: str + lastName: str + +schema Person: + name: Name + age: int + +schema Group: + name: str + persons: [Person] +``` + +To config a group: + +```python +group = Group { + name = "group" + persons = [{ + name = { + firstName = "John" + lastName = "Doe" + } + age = 24 + }] +} +``` + +- Top-level schema name is required to config a schema. +- The schema of the attributes in the schema can be omitted. + +Multi-level nested schemas will make the configuration verbose. KCL supports defining attributes in the schema through `selector expression`. The selector form is **x.y.z**, see the following example: + +```python +group = Group { + name = "group" + persons = [{ + name.firstName = "John" + name.lastName = "Doe" + age = 24 + }] +} +``` + +- Selector can be used to represent attribute in a schema + +### Inheritance + +Inheritance is an effective means to define a hierarchical structure definition, and KCL supports limited **single inheritance** of the schema. + +```python +schema Person: + firstName: str + lastName: str + +# schema Scholar inherits schema Person +schema Scholar(Person): + fullName: str = firstName + '_' + lastName + subject: str + +JohnDoe = Scholar { + firstName = "John", + lastName = "Doe", + subject = "CS" +} +``` + +The result is a **dict**: + +```python +{ + 'JohnDoe': { + 'firstName': 'John' + 'lastName': 'Doe' + 'fullName': 'John Doe' + 'subject': 'CS' + } +} +``` + +Each schema can be treated as a separated function context. Statements, including attribute statements and init statements, in the context of schemas will be evaluated from base schema to subschema according to the inheritance order. Each schema context is evaluated only once sequentially. The same goes for expressions in the check block. In the example, firstName and lastName are configured in the context of Person schema, and fullName is formed by splicing firstName and lastName in the context of Scholar schema. + +The default value can be modified in each schema. Value defined in **Configuration Definition** has a higher priority than the default value. Attributes with default values in any schema context ​​will eventually be unioned by configuration data. References to attributes in the schema context statements will use the value with unioned configuration data on evaluating at runtime. For example: + +```python +schema a: + x = 1 + y = x * 2 + +schema b(a): + x = 2 + +v = a { + x = 3 +} + +``` + +The result is a **dict**: + +```python +{ + 'v': { + 'x': 3 + 'y': 6 + } +} +``` + +Notes: + +- Report an error if inheriting more than one base schema. +- The type of the base schema attribute cannot be modified in the subschema. +- Report an error if inheriting a **mixin**. +- Report an error when a circular dependency occurs. + +Limitations: + +Since inheritance will derive some complex demands, we are cautious about these complex demands. There are still some restrictions on inheritance, and it's still under discussion. + +- KCL provides limited and deterministic polymorphism support, more complex and flexible polymorphism support, such as **self**, **super** keywords, are temporarily not included in the schema definition. +- Currently, KCL only supports the polymorphism of the inherited attributes of the schema, and does not support the polymorphism of the expressions in the check block. +- For the case of multiple levels of schema inheritance, the schema arguments can only be passed to the last level of sub-schema. + +### Mixin + +In addition to **composition** and **inheritance**, KCL supports declarative reuse of schema code through the **mixin** mechanism. To use a mixin, we only need to declare the **mixin** in the schema definition. + +The **mixin** syntax is the following: + +```bnf +//////////// mixin_stmt //////////// +mixin_stmt: "mixin" "[" [mixins | multiline_mixins] "]" "\n" +multiline_mixins: "\n" _INDENT mixins "\n" _DEDENT +mixins: operand_name ("," ("\n" mixins | operand_name))* +``` + +Here is a simple example: + +```python +schema Person: + mixin [FullNameMixin] + firstName: str = "default" + lastName: str + +schema FullNameMixin: + fullName: str = "{} {}".format(firstName, lastName) + +JohnDoe = Person { + firstName = "John" + lastName = "Doe" +} +``` + +The result is a **dict**: + +```python +{ + 'JohnDoe': { + 'firstName': 'John' + 'lastName': 'Doe' + 'fullName': 'John Doe' + } +} +``` + +Multiple mixins can be added to a single schema, and mixins context will be evaluated after the host schema context at runtime. In the inheritance scenario, the mixin context can be regarded as a part of the host schema context, and the overall evaluation of schema context order is not affected. + +Notes: + +- The name of **mixin** schema must end with 'Mixin', otherwise an error will be reported. +- The attributes referenced in the **mixin** must be defined in the **mixin** itself or host schema, otherwise an error will be reported. + +### Protocol + +In addition to schema, an additional type definition method `protocol` is provided in KCL, and its properties are as follows: + +- In a protocol, only attributes and their types can be defined, complex logic and check expressions cannot be written, and mixins cannot be used. +- A protocol can only inherit or refer to other protocols, but cannot inherit or refer to other schemas. + +We can use **protocol** to add an optional host type to the dynamically inserted **mixin**. + +The **mixin** can define its host type through the `for` keyword, and internally it will query the type corresponding to the attribute from the host type. + +```python +protocol DataProtocol: # A mixin host type + data: str + +mixin DataMixin for DataProtocol: # Using the `for` keyword to define a mixin host type + x: int = data # The type of `data` is `str`, which is from `data` of `DataProtocol` +``` + +In `DataMixin`, the `data` attribute is obtained according to the `DataProtocol` host type as `str` type, and then a type error will occur when the value is assigned to `x` of type `int`: + +```python +protocol DataProtocol: + data: str + +mixin DataMixin for DataProtocol: + x: int = data # Error: expect int, got str + x: str = data # Error: can't change schema field type of 'x' from int to str +``` + +Please note that the host type **protocol** can only be used for **mixin** definitions (the suffix name is `Mixin`), otherwise an error will be reported. + +```python +protocol DataProtocol: + data: str + +schema Data for DataProtocol: # Error: only schema mixin can inherit from protocol + x: str = data +``` + +### Schema Context Evaluation + +The schema definition is composed of attribute statements, configuration data, init statements, mixins, and checks. In a separate schema context, the evaluation top-down order is as follows: + +``` +|------------------------------------------| +| attribute defaulting | +|------------------------------------------| +| configuration union | +|------------------------------------------| +| attribute templating | +|------------------------------------------| +| statements in declaration order | +|------------------------------------------| +| mixins in declaration order | +|------------------------------------------| +| check expressions in any order | +|------------------------------------------| +``` + +In the case of schema inheritance, each schema context is evaluated from the base schema in the order of inheritance, and each context is evaluated only once. +Suppose there are schemas a, b, and c, where c inherits b and b inherits a. Schema contexts will be evaluated in top-down order as: + +``` +|-----------------| +| schema a | +|-----------------| +| schema b | +|-----------------| +| schema c | +|-----------------| +``` + +### Members + +Built-in function and members of schema + +- instances(full_pkg: bool = False) + Return the list of existing instances of a schema in the main package. When the `full_pkg` is set `True`, return all schema instances in the whole program. + +### Irrelevant Order Calculation + +The irrelevant order calculation in the schema indicates the reference relationship between the internal attributes of the schema. For example, when we declare an expression of the form `a = b + 1`, the calculation of the value of `a` depends on the calculation of the value of `b`. When the compiler calculate the value of `a` and the value of `a` depends on the value of `b`, the compiler will choose to first calculate the value of `b`, and then calculate the value of a according to the expression `a = b + 1`, which is slightly different from the calculation method of traditional procedural language the difference. + +Since the calculation of values in the schema is based on dependencies, just like a directed acyclic graph traverses each node in the graph according to the order of topological sorting, the order of declaration of attributes in the schema is not so important, so the feature is called the irrelevant order calculation. + +Please note that there can be no circular references between different schema attribute values. + +We can see this feature through the following examples. + +```python +schema Person: + name?: str + age: int = _age + + _age = 10 + + if name == "Son": + _age = 18 + +schema Son(Person): + name: str = "Son" + +person = Person {} +son = Son {} +``` + +The output is + +```yaml +person: + name: null + age: 10 +son: + name: Son + age: 18 +``` + +Besides, we can achieve KCL polymorphism such as + +```python +schema Person: + name?: str + _age: int = _age + + _age = 10 + if name == "Son": + _age = 18 + elif name == "SonConf": + _age = 24 + +schema Son(Person): + name: str = "Son" + +person = Person() {} +son = Son() { + name = "SonConf" +} +``` + +The output is + +```yaml +person: + name: null + age: 10 +son: + name: SonConf + age: 24 +``` + +More examples: + +```python +schema Fib: + n1: int = n - 1 + n2: int = n1 - 1 + n: int + value: int = _value + + if n <= 2: + _value = 1 + else: + _value = (Fib {n = n1}).value + (Fib {n = n2}).value + +fib8 = (Fib {n = 8}).value +``` + +The output is + +```yaml +fib8: 21 +``` + +As in the above examples, we can see that in the schema, we only need to simply specify the dependency between attributes, and the compiler will automatically calculate the value based on the dependency, which can help us save a lot of boilerplate code and reduce configuration difficulty of writing. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/statements.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/statements.md new file mode 100644 index 000000000..179410b54 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/statements.md @@ -0,0 +1,185 @@ +--- +title: "Statements" +linkTitle: "Statements" +type: "docs" +weight: 2 +description: Statements +--- + +## Syntax + +In KCL, statements consist of small statements and compound statements. The syntax is the following: + +```bnf +preamble_statement: preamble_small_stmt | preamble_compound_stmt +preamble_small_stmt: (small_stmt | import_stmt) NEWLINE +preamble_compound_stmt: compound_stmt | schema_stmt +statement: small_stmt NEWLINE | compound_stmt +compound_stmt: if_stmt +small_stmt: assign_stmt | expr_stmt | assert_stmt +``` + +The preamble statement is used to define the module level statements, consist of `statement`, `import_stmt`, and `schema_stmt`. The statement is used to define the block level statements, which are used in the `if` statement and `schema` statement. + +### Small Statements + +A small statement is comprised of a single logical line. Multiple statements in one-line are not allowed. + +#### Assignment Statements + +Generally, assign_stmt is divided into assignment and augmented assignment. The syntax is the following: + +```bnf +assign_stmt: target_primary (":" type) ("=" target_primary)* "=" test | target_primary aug_assign test +aug_assign: "+=" | "-=" | "*=" | "**=" | "/=" | "//=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" +target_primary: identifier | target_primary DOT identifier +``` + +An assignment statement has the form `lhs = rhs`. It evaluates the expression on the right-hand side then assigns its value (or values) to the variable (or variables) on the left-hand side. + +The **target_primary** on the left-hand side is an `identifier` or an `identifier` followed by select dots. + +Note: When using **target_primary** will cause collisions, use **primary_expr** as an alternative. + +Examples: + +```python +k = 1 +a.b = "a.b" +``` + +To keep it simple, the compound target is not supported as **target_primary**. + +The right value of an assignment statement is a conditional expression, which is discussed separately. + +An augmented assignment, which has the form `lhs op= rhs` updates the variable `lhs` by applying a binary arithmetic operator op (one of +, -, \*, /, //, %, &, |, ^, <<, >>) to the previous value of `lhs` and the value of `rhs`. + +The **target_primary** on the left-hand side is the same as assignment statement. Examples: + +```python +_x -= 1 +_filename += ".k" +``` + +There is no concept of in-place modification in KCL. The `aug_assign` statement will modify a copy of the **target_primary** and assign the copy to **target_primary**. + +In particular, in KCL, the `|=` symbol represents the **union** operation, which is defined as follows: + +- The behavior of the **union** operation needs to be consistent with the behavior of the **configuration definition**. + +See **expressions** spec for more details of union operator in **Arithmetic Operations**. + +#### Expression Statements + +An expression statement evaluates an expression and discards its result. + +Syntax: + +```bnf +expr_stmt: expression +``` + +An expression statement supported in KCL is function invocation expression, which is discussed in **expression** spec. + +```python +print(k) # print a variable +``` + +#### Import Statements + +Import statements are used to **search** and **load** a module, and define a name or names in the local namespace for the scope where the import statement occurs. + +Syntax: + +```bnf +import_stmt: "import" dot_name ("as" NAME)? +dot_name: [leading_dots] identifier (DOT identifier)* +leading_dots: "."+ +``` + +Examples: + +```python +import math # import a built-in module math +import pkg # import pkg +import pkg.foo # import pkg.foo +import pkg.subpkg # import a subpkg in a pkg +import .pkg2.subpkg3 # import a subpkg in a pkg inside of current pkg +import ...pkg2 # Go two levels up then import pkg2 +``` + +See **module** spec for more details of module spec. + +#### Assert Statements + +Assert statements are a convenient way to insert debugging assertions into KCL code. + +The syntax is the following: + +``` +assert_stmt: ASSERT test ("if" test)? ("," test)? +``` + +The conditional expression in assert will be evaluated and get a boolean. Report an error if returning a `False`. + +Examples: + +```python +assert: x > 1 # report an error on x <= 1 +``` + +#### Conditional Statements + +KCL allows using conditional statements to control the instructions to +be executed. They are also called the control-flow statements. + +The only type of control-flow syntax is the well-known `if-elif-else` syntax. + +The syntax of the `if-elif-else` statement is the following. + +```bnf +if_stmt: "if" test ":" suite ("elif" test ":" suite)* (ELSE ":" suite)? +suite: small_stmt | NEWLINE _INDENT statement+ _DEDENT +``` + +An `if` or `elif` statement evaluates a given expression. When the expression +is evaluated to `True`, a list of statements following `:` are executed. + +The following is an example: + +```python +a = 10 +if a == 0: + print("a is zero") +elif a < 100: + print("a < 100") + print("maybe a is negative") +else: + print("a >= 100") +``` + +`if-elif-else` statements can be nested. For example: + +```python +a = 10 +if a == 0: + print("a is zero") +elif a < 100: + print("a < 100") + if a < 0: + print("a is negative") + print("No matter a is negative or positive, this message is printed") +else: + print("a >= 100") +``` + +#### Schema Statements + +Schema statements are used to define a type of configuration data. The syntax is the following: + +```bnf +schema_stmt: [decorators] "schema" identifier ["[" [arguments] "]"] ["(" operand_name ")"] ":" NEWLINE [schema_body] +schema_body: _INDENT (string NEWLINE)* [mixin_stmt] (schema_attribute_stmt | statement)* [check_block] _DEDENT +``` + +See **schema** spec for more details of schema spec. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/variables.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/variables.md new file mode 100644 index 000000000..b3e1c539a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/spec/variables.md @@ -0,0 +1,68 @@ +--- +title: "Variables" +linkTitle: "Variable" +type: "docs" +weight: 2 +description: Variable +--- + +In KCL, variables can be defined using assign statements. For example, the following statement defines a variable `spam` to a string `"ham"`. + +```python +spam = "ham" +``` + +There are two types of variables, which are global variables and list comprehension local variables. + +- A global variable is defined not within any context. +- A comprehension local variable is defined inside a comprehension. + +A variable can be used after definition, until the end of the current scope. + +For a global variable, the scope is the module it is defined in. Note that a module can consists of multiple source files. + +For a list comprehension local variable, the scope is the list comprehension it is defined in. + +More information on modules, list comprehensions and scopes will be discussed in later chapters. + +## Immutability + +Global variables are immutable. In other words, once defined such a variable cannot be redefined (or, i.e., modified). + +The following code is illegal, and KCL will report an error during evaluation. + +```python +spam = "ham" +spam = "eggs" # Error: The immutability rule is violated! +``` + +- A variable starts with the `_` character is mutable. + +```python +_spam +cond = True +if cond: + _spam = "ham" +else: + _spam = "eggs" +``` + +## Variable Exporting + +As shown in the preview chapter, KCL is able to export evaluation results to the standard output according to a target data format. + +The rules are the followings: + +- Living global variables at the end of an evaluation will be dumped out. +- If the name of a variable starts with the `_` character, it will not be dumped out. + +## Uniqueness of Exported Variable Identifier + +Each exported variable identifier must be unique in its package, so that an exported variable could be located uniquely by package location path and variable identifier, such as 'a.b.c:var', in which 'a.b.c' locates a package. + +Two variable identifiers are different if: + +- they are spelled differently +- they are defined in different packages and are not compiled in a single execution + +Identifying an exported variable should be supported by the kcl compiler, which needs to provide corresponding identifying features through the command line and api form. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/tour.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/tour.md new file mode 100644 index 000000000..c724d2bc3 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/tour.md @@ -0,0 +1,3281 @@ +--- +title: "KCL 之旅" +sidebar_position: 1 +--- + +本文展示了如何使用 KCL 的核心特性,包含变量、运算符、schema 和库,前提是您有使用其他语言编程的经验。KCL 主要受 Python 启发,了解 Python 对学习 KCL 非常有帮助。 + +### 重要概念 + +在学习 KCL 语言时,请牢记以下事实和概念: + +- KCL 是一种配置策略语言。它为编写配置和策略提供了简单且自洽的语言设计和库支持。它不能用于应用程序开发或其他通用编程语言(GPL)支持的场景。 +- KCL 吸收了经典 **OOP** 的元素,并且提供了**类型**、**复用**和**合并**等简单、开发人员友好、可靠且利于传播的配置编写实践。 +- KCL 更倾向于**不可变性**,建议使用**合并**来添加增量的变更。不可变性降低了副作用,例如不可预测的问题。 +- KCL 的 **schema** 结构体定义了严格的属性和静态类型,并且支持表达式验证。**schema** 结构体主要由带类型的属性、schema 上下文和检查块构成。 +- KCL 的 **config** 是一个类 **JSON** 表达式,通过它我们可以复用 schema 的完整定义。KCL 通过分离 schema 和 config 来提供定义和配置的能力。 +- KCL 的 **rule** 是一个书写规则约束表达式的结构,可用于数据校验和策略编写。 +- KCL 的代码文件以包(目录)和模块(文件)的形式进行管理。同一包中的 schema 彼此可见;跨包的数据需要通过 **import 语句**导入。包级变量虽然可以导出,但是它们不能被其他包修改。 +- KCL 语法定义主要使用声明式表达式,并且只提供少量必要的声明式语句,例如 import、 if...else、assert、assignment 以及 schema。 +- 没有主函数,每个 `.k` 文件可以作为单独的配置文件执行。 +- 支持**内置函数**和**插件**以简化编写。 + +### 关键字 + +下表列出了 KCL 语言的关键字。 + +```txt +True False None Undefined import +and or in is not +as if else elif for +schema mixin protocol check assert +all any map filter lambda +rule +``` + +### 标识符 + +在 KCL 中, 标识符是标识一个值的名称,可以带有选择器。 + +- 标识符由字母、数字、下划线或前缀 `$` 组成。 +- 标识符不能与关键字重复,除非它们有 `$` 前缀。 +- 标识符不得包含任何嵌入的空格或符号。 +- 可以在标识符中的任何位置使用字母和下划线。 +- 数字不能放在标识符的第一位。 +- `$` 字符只能放在标识符的第一个位置。 + +示例: + +```python +x +a +b1 +b_2 +_c +$if +``` + +为了简化限定标识符(例如 `pkg.type`)的定义,我们还定义了 `qualified identifier`: + +示例: + +```python +pkg.a +``` + +在 `qualified identifier` 中的包名必须通过 `import` 关键字导入。 + +#### 标识符前缀 + +使用 `$` 前缀符号定义关键字标识符。 + +```python +$if = 1 +$else = "s" +``` + +请注意,非关键字标识符是否有 `$` 符号都是同样的效果。 + +```python +_a = 1 +$_a = 2 # equal to `_a = 2` +``` + +### 变量 + +以下是如何创建并实例化变量的例子: + +```python +name = "Foo" # Declare a variable named `name` and its value is a string literal "Foo" +``` + +它对应了如下 YAML 输出: + +```yaml +name: Foo +``` + +在 KCL 中,我们可以通过定义包级变量将变量导出为配置数据。使其直接、清晰、可维护。导出的变量是不可变的。因此一旦声明它,就无法对其进行修改,例如,假设我们有一个名为 `example.k` 的配置文件,变量 `name` 在声明后就禁止修改,就像标准的命令式语言一样。 + +```python +name = "Foo" # exported + +... + +name = "Bar" # error: a exported declaration variable can only be set once. +``` + +作为补充,我们可以在模块级别定义一个非导出变量,这个变量是可变的,不会显示在 YAML 输出当中。 + +```python +_name = "Foo" # _ variables are not output to YAML and are mutable +_name = "Bar" +``` + +请注意,变量的名称不能为 `True`、`False`、`None` 或者 `Undefined`,因为它们与 KCL 内置的名称常量之间存在二义性。 + +```python +False = 1 # Error +True = False # Error +None = Undefined # Error +Undefined = None # Error +``` + +### 内置类型 + +KCL 支持以下类型: + +- 数字 +- 字符串 +- 布尔 +- 列表 +- 字典 + +#### 数字 + +KCL 的数字类型有两种形式: + +- 64 位有符号整数。值的范围为 -9223372036854775808~9223372036854775807. +- 64 位浮点数,遵循 IEEE 754 标准。我们不建议在配置中使用 float 类型,我们可以使用字符串代替并在运行时进行解析。 + +整数和浮点数都支持基本运算符,例如 `+`,`-`,`/` 和 `*`,而复杂的运算,例如 `abs()`, `ceil()` 和 `floor()`,都是通过内置的数学库来支持。 + +整数是不带小数点的数字。以下是一些定义整数的例子: + +```python +a = 1 +b = -1 +c = 0x10 # hexadecimal literal +d = 0o10 # octal literal +e = 010 # octal literal +f = 0b10 # binary literal +g = int("10") # int constructor +``` + +如果一个数字包含小数点,则它是浮点数。以下是一些浮点数的示例: + +```python +a = 1.10 +b = 1.0 +c = -35.59 +d = 32.3e+18 +f = -90. +h = 70.2E-12 +i = float("112") # float constructor +``` + +内置数学库可用于数字类型: + +```python +import math + +assert abs(-40) == 40 +assert round(70.23456) == 70 +assert min(80, 100, 1000) == 80 +assert max(80, 100, 1000) == 1000 +assert sum([0,1,2]) == 3 +assert math.ceil(100.12) == 101.0 +assert math.floor(100.12) == 100.0 +assert math.pow(100, 2) == 10000.0 +``` + +KCL 默认使用 64 位数字类型。我们可以在 KCL 命令行使用 `-r` 参数执行严格的 32 位范围检查。 + +```bash +kcl main.k -r -d +``` + +请注意,为了性能考虑该功能只能在 `debug` 模式中使用。 + +##### 单位字面值 + +在 KCL 中,我们可以给一个整数添加如下的单位后缀,这不影响它的真实值。 + +- 通用整形和定点数: `P`, `T`, `G`, `M`, `K`, `k`, `m`, `u`, `n` +- 2 的幂: `Pi`, `Ti`, `Gi`, `Mi`, `Ki` + +```python +# SI +n = 1n # 1e-09 +u = 1u # 1e-06 +m = 1m # 1e-03 +k = 1k # 1000 +K = 1K # 1000 +M = 1M # 1000000 +G = 1G # 1000000000 +T = 1T # 100000000000 +P = 1P # 1000000000000000 +# IEC +Ki = 1Ki # 1024 +Mi = 1Mi # 1024 ** 2 +Gi = 1Gi # 1024 ** 3 +Ti = 1Ti # 1024 ** 4 +Pi = 1Pi # 1024 ** 5 +``` + +此外,我们还可以使用定义在 `units` 模块中的单位常量: + +```python +import units + +n = 1 * units.n # 1e-09 +u = 1 * units.u # 1e-06 +m = 1 * units.m # 1e-03 +k = 1 * units.k # 1000 +K = 1 * units.K # 1000 +M = 1 * units.M # 1000000 +G = 1 * units.G # 1000000000 +T = 1 * units.T # 1000000000000 +P = 1 * units.P # 1000000000000000 +# IEC +Ki = 1 * units.Ki # 1024 +Mi = 1 * units.Mi # 1024 ** 2 +Gi = 1 * units.Gi # 1024 ** 3 +Ti = 1 * units.Ti # 1024 ** 4 +Pi = 1 * units.Pi # 1024 ** 5 +``` + +我们还可以使用定义在 `units` 模块内的整数和单位字符串之间的转换函数 + +```python +import units +# SI +K = units.to_K(1000) # "1K" +M = units.to_M(1000000) # "1M" +G = units.to_G(1000000000) # "1G" +T = units.to_T(1000000000000) # "1T" +P = units.to_P(1000000000000000) # "1P" +# IEC +Ki = units.to_Ki(1024) # "1Ki" +Mi = units.to_Mi(1024 ** 2) # "1Mi" +Gi = units.to_Gi(1024 ** 3) # "1Gi" +Ti = units.to_Ti(1024 ** 4) # "1Ti" +Pi = units.to_Pi(1024 ** 5) # "1Pi" +``` + +```python +import units +# SI +K = units.to_K(int("1M")) # "1000K" +M = units.to_M(int("1G")) # "1000M" +G = units.to_G(int("1T")) # "1000G" +T = units.to_T(int("1P")) # "1000T" +P = units.to_P(int("10P")) # "10P" +# IEC +Ki = units.to_Ki(int("1Mi")) # "1024Ki" +Mi = units.to_Mi(int("1Gi")) # "1024Mi" +Gi = units.to_Gi(int("1Ti")) # "1024Gi" +Ti = units.to_Ti(int("1Pi")) # "1024Ti" +Pi = units.to_Pi(int("10Pi")) # "10Pi" +``` + +单位类型定义在 `units` 模块中,单位类型的值不能进行任何四则运算。 + +```python +import units + +type NumberMultiplier = units.NumberMultiplier + +x0: NumberMultiplier = 1M # Ok +x1: NumberMultiplier = x0 # Ok +x2 = x0 + x1 # Error: unsupported operand type(s) for +: 'number_multiplier(1M)' and 'number_multiplier(1M)' +``` + +我们可以使用 `int()`、`float()` 和 `str()` 函数将数值单位类型转换为数字类型或字符串类型。 + +```python +a: int = int(1Ki) # 1024 +b: float = float(1Ki) # 1024.0 +c: str = str(1Mi) # "1Mi" +``` + +#### 字符串 + +字符串是一个不可变的 Unicode 字符序列。我们可以使用单引号或双引号创建字符串: + +```python +'allows embedded "double" quotes' # Single quotes +"allows embedded 'single' quotes" # Double quotes +'''Three single quotes''', """Three double quotes""" # Triple quoted +``` + +三引号用于定义多行字符串。 + +```python +"""This is a long triple quoted string +may span multiple lines. +""" +``` + +请注意,KCL 的单引号和双引号字符串的使用几乎没有区别。唯一可以简化的是,我们不需要在单引号字符串中转义双引号,也不需要在双引号中转义单引号。 + +```python +'This is my book named "foo"' # don't need to escape double quotes in single quoted strings. +"This is my book named 'foo'" # don't need to escape single quotes in double quoted strings. +``` + +我们可以使用 `+` 操作符连接字符串: + +```python +x = 'The + operator ' + 'works, as well.' +``` + +我们可以使用 `str` 内置函数将 int 或 float 转为字符串: + +```python +x = str(3.5) # "3.5" +``` + +可以使用很多内置的字符串函数: + +```python +x = "length" +assert len(x) == 6 # True +assert x.capitalize() == "Length" +assert x.count("gt") == 1 +assert x.endswith("th") == True +assert x.find("gth") == 3 +assert "{} {}".format("hello", "world") == 'hello world' +assert x.index("gth") == 3 +assert x.isalnum() == True +assert x.isalpha() == True +assert "123456".isdigit() == True +assert x.islower() == True +assert " ".isspace() == True +assert "This Is Title Example".istitle() == True +assert x.isupper() == False +assert "|".join(["a", "b", "c"]) == "a|b|c" +assert "LENGTH".lower() == "length" +assert ' spacious '.lstrip() == 'spacious ' +assert x.replace("th", "ht") == "lenght" +assert "lengthlength".rfind("le") == 6 +assert "lengthlength".rindex("le") == 6 +assert "length length".rsplit() == ["length", "length"] +assert "length ".rstrip() == "length" +assert "length length".split() == ["length", "length"] +assert 'ab c\n\nde fg\rkl\r\n'.splitlines() == ['ab c', '', 'de fg', 'kl'] +assert "length".startswith('len') == True +assert "***length***".strip('*') == "length" +assert "length length".title() == "Length Length" +assert x.upper() == "LENGTH" +``` + +格式化字符串有两种使用方法: 使用 `"{}".format()` 内置函数, 或者使用花括号指定变量并使用 `$` 标记取变量值。在 KCL 中叫做**插值字符串**。在下面的例子中,`a` 和 `b` 的值都是 `"hello world"`。 + +此外,要序列化的变量可以以特殊的数据格式提取,例如 YAML 或 JSON。在这种情况中,`#yaml` 或 `#json` 可以包含在花括号中。 + +注意,如果不想 `${...}` 表示字符串插值 ,我们可以在 `$` 之前添加`\` 字符表示直接以字符串的形式输出 `${...}`。 + +```python +world = "world" +a = "hello {}".format(world) # "hello world" +b = "hello ${world}" # "hello world" +c1 = "$hello ${world}$" # "$hello world$" +c2 = "$" + "hello ${world}" + "$" # "$hello world$" +c3 = "$" + "hello \${world}" + "$" # "$hello ${world}$" + +myDict = { + "key1" = "value1" + "key2" = "value2" +} +myList = [1, 2, 3] + +d = "here is myDict in json: ${myDict: #json}" +# d: 'here is myDict in json: {"key1": "value1", "key2": "value2"}' + +e = "here is myDict in yaml:\n${myDict: #yaml}" +# e: | +# here is myDict in yaml: +# key1: value1 +# key2: value2 + +f = "here is myList in json: ${myList: #json}" +# f: 'here is myList in json: [1, 2, 3]' +g = "here is myList in yaml: ${myList: #yaml}" +# g: | +# here is myList in yaml: - 1 +# - 2 +# - 3 +``` + +此外,我们可以在上面的示例代码输出 **YAML 字符串** 中看到一些符号,例如 `|`、`>`、`+`、`-`。 + +- `|` 表示 **块文字样式**,指示块内换行符的行为方式。 +- `>` 表示块标量中的**块折叠样式**,换行符将被空格替换。 +- `+` 和 `-` 是 **block chomping 指示符**,用于控制字符串末尾的换行符。 默认值 **clip** 在字符串的末尾放置一个换行符。 要删除所有换行符,请通过在样式指示符 `|` 或 `>` 后面添加 `-` 来**删除**它们。 clip 和 strip 都忽略块末尾实际有多少换行符; 在样式指示符后面添加一个 `+` 来**保留**它们。 + +例如,**strip 块文字样式** yaml 字符串是 + +```yaml +example: |- + Several lines of text, + with some "quotes" of various 'types', + and also a blank line: + + plus another line at the end. +``` + +结果为: + +```plain +Several lines of text, +with some "quotes" of various 'types', +and also a blank line: + +plus another line at the end. +``` + +更多信息可见 [Yaml Multiline String](https://yaml-multiline.info/) 和 [YAML Specification v1.2](https://yaml.org/spec/1.2.1/) 。 + +##### 原始字符串 + +KCL 原始字符串是通过在字符串字面值前加上 `'r'` 或 `'R'` 来创建的。 KCL 原始字符串将反斜杠 (`\`) 和字符串插值 (`${}`) 视为普通的非字符。当我们想要一个包含反斜杠、字符串插值的字符串并且不希望它们被视为转义字符时,原始字符串是很有用的。 + +- 对于包含反斜杠(`\`)的原始字符串,KCL 代码和输出 YAML 如下: + +```python +s = "Hi\nHello" +raw_s = r"Hi\nHello" # This is a KCL raw string with the `r` prefix. +``` + +```yaml +s: |- + Hi + Hello +raw_s: Hi\nHello +``` + +- 对于包含字符串插值(`${}`)的原始字符串,KCL 代码和输出 YAML 如下: + +```python +worldString = "world" +s = "Hello ${worldString}" +raw_s = r"Hello ${worldString}" # This is a KCL raw string with the `r` prefix. +``` + +```yaml +worldString: world +s: Hello world +raw_s: Hello ${worldString} +``` + +此外,原始字符串最常用的场景是在正则表达式中使用: + +```python +import regex + +key = "key" +result = regex.match(key, r"[A-Za-z0-9_.-]*") # True +``` + +#### 布尔值 + +布尔值有两个常量对象:`False` 和 `True`. + +```python +a = True +b = False +``` + +#### List + +List 是一个序列,通常用于存储同质项的集合。下面是一个简单的 KCL 列表的例子: + +```python +list = [1, 2, 3] +assert len(list) == 3 # True +assert list[0] == 1 # True +``` + +我们可以使用列表推导式构建列表: + +```python +list = [ _x for _x in range(20) if _x % 2 == 0] +assert list == [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # True +``` + +并且还可以使用嵌套的列表推导式: + +```python +matrix = [[1, 2], [3,4], [5,6], [7,8]] +transpose = [[row[_i] for row in matrix] for _i in range(2)] +assert transpose == [[1, 3, 5, 7], [2, 4, 6, 8]] # True +``` + +此外,我们可以在列表推导式中使用两个变量。第一个变量表示列表中的索引,第二个变量表示列表中的项。 + +```python +data = [1000, 2000, 3000] +# Single variable loop +dataLoop1 = [i * 2 for i in data] # [2000, 4000, 6000] +dataLoop2 = [i for i in data if i == 2000] # [2000] +dataLoop3 = [i if i > 2 else i + 1 for i in data] # [1000, 2000, 3000] +# Double variable loop +dataLoop4 = [i + v for i, v in data] # [1000, 2001, 3002] +dataLoop5 = [v for i, v in data if v == 2000] # [2000] +# Use `_` to ignore loop variables +dataLoop6 = [v if v > 2000 else v + i for i, v in data] # [1000, 2001, 3000] +dataLoop7 = [i for i, _ in data] # [0, 1, 2] +dataLoop8 = [v for _, v in data if v == 2000] # [2000] +``` + +我们可以通过 `+` 连接列表: + +```python +_list0 = [1, 2, 3] +_list1 = [4, 5, 6] +joined_list = _list0 + _list1 # [1, 2, 3, 4, 5, 6] +``` + +我们可以使用解包操作符 `*` 合并多个列表: + +```python +_list0 = [1, 2, 3] +_list1 = [4, 5, 6] +union_list = [*_list0, *_list1] # [1, 2, 3, 4, 5, 6] +``` + +我们可以使用 `if` 表达式动态的将元素添加到列表,符合条件的元素会被添加到列表,不符合条件的元素会被忽略。 + +```python +a = 1 # 1 +data = [ + 1 + if a == 1: 2 + if a > 0: 3 + if a < 0: 4 +] # [1, 2, 3] +``` + +```python +a = 1 # 1 +data1 = [ + 1 + if a == 1: + 2 + elif a == 2: + 3 + else: + 3 +] # [1, 2] +data2 = [ + 1 + if a == 1: 2 + elif a == 2: 2 + else: 3 +] # [1, 2] +``` + +我们可以合并(union)列表: + +```python +_list0 = [1, 2, 3] +_list1 = [4, 5, 6] +union_list = _list0 | _list1 # [4, 5, 6] +``` + +我们可以使用 `for k in list_var` 表达式遍历列表: + +```python +data = [1, 2, 3] +dataAnother = [val * 2 for val in data] # [2, 4, 6] +``` + +#### Dict + +Dict 是将可哈希的值映射到任意对象的映射对象。字典是有序的。键的顺序遵循其声明的顺序: + +这里有几个简单的 KCL 字典: + +```python +a = {"one" = 1, "two" = 2, "three" = 3} +b = {'one' = 1, 'two' = 2, 'three' = 3} +assert a == b # True +assert len(a) == 3 # True +``` + +在写多行的键-值时,可以省略每个键-值对行尾的逗号 `,`: + +```python +data = { + "key1" = "value1" # Ignore the comma ',' at the end of line + "key2" = "value2" +} # {"key1": "value1", "key2": "value2"} +``` + +在 Dict 键上使用简单的字面值时可以省略引号: + +```python +data = { + key1 = "value1" # Ignore key quotation '"' + key2 = "value2" +} # {"key1": "value1", "key2": "value2"} +``` + +请注意,当属性中存在 `-` 和 `.` 等其他连字符时,我们必须使用引号。 + +```python +data = { + "config.dot.attr" = "value1" # Note we use `"config.dot.attr"` instead of `config.dot.attr` here. + "config-hyphen-attr" = "value2" # Note we use `"config-hyphen-attr"` instead of `config-hyphen-attr` here. +} +``` + +此外,**选择表达式**可以用于定义包含嵌套键 dict 实例。 + +```python +person = { + base.count = 2 + base.value = "value" + labels.key = "value" +} # {"base": {"count": 2, "value": "value"}, "labels": {"key": "value"}} +``` + +输出 YAML 为: + +```yaml +person: + base: + count: 2 + value: value + labels: + key: value +``` + +在 KCL 中,dict 中的不同的字段可以直接引用,比如如下的例子 + +```python +config = { + name = "me" + metadata.name = name # Reference `name` with the value `"me"` in `config` directly. +} +``` + +输出 YAML 为: + +```yaml +config: + name: me + metadata: + name: me +``` + +我们可以使用字典推导式构建字典: + +```python +x = {str(i): 2 * i for i in range(3)} +assert x == {"0" = 0, "1" = 2, "2" = 4} +``` + +此外,我们可以在字典推导式中使用两个变量。第一个变量表示字典的键,第二个变量表示字典中键对应的值。 + +```python +data = {key1 = "value1", key2 = "value2"} +# Single variable loop +dataKeys1 = {k: k for k in data} # {"key1": "key1", "key2": "key2"} +dataValues1 = {k: data[k] for k in data} # {"key1": "value1", "key2": "value2"} +# Double variable loop +dataKeys2 = {k: k for k, v in data} # {"key1": "key1", "key2": "key2"} +dataValues2 = {v: v for k, v in data} # {"value1": "value1", "value2": "value2"} +dataFilter = {k: v for k, v in data if k == "key1" and v == "value1"} # {"key1": "value1"} +# Use `_` to ignore loop variables +dataKeys3 = {k: k for k, _ in data} # {"key1": "key1", "key2": "key2"} +dataValues3 = {v: v for _, v in data} # {"value1": "value1", "value2": "value2"} +``` + +我们可以使用解包操作符 `**` 来合并字典: + +```python +_part1 = { + a = "b" +} + +_part2 = { + c = "d" +} + +a_dict = {**_part1, **_part2} # {"a: "b", "c": "d"} +``` + +此外,union 操作符 `|` 也能达到同样的效果: + +```python +_part1 = { + a = "b" +} + +_part2 = { + c = "d" +} + +a_dict = _part1 | _part2 # {"a: "b", "c": "d"} +``` + +我们可以使用 `if` 表达式动态的将元素添加到字典,符合条件的元素会被添加到字典,不符合条件的元素会被忽略。 + +```python +a = 1 # 1 +data = { + key1 = "value1" + if a == 1: key2 = "value2" + if a > 0: key3 = "value3" + if a < 0: key4 = "value4" +} # {"key1": "value1", "key2": "value2", "key3": "value3"} +``` + +```python +a = 1 # 1 +data1 = { + key1 = "value1" + if a == 1: + key2 = "value2" + elif a > 0: + key3 = "value3" + else: + key4 = "value4" +} # {"key1": "value1", "key2": "value2"} +data2 = { + key1 = "value1" + if a == 1: key2 = "value2" + elif a > 0: key3 = "value3" + else: key4 = "value4" +} # {"key1": "value1", "key2": "value2"} +``` + +我们可以使用 `for k in dict_var` 表达式来遍历字典, 并且可以使用 `in` 操作符来判断 dict 是否包含某个键。 + +```python +data = {key1 = "value1", key2 = "value2"} +dataAnother = {k: data[k] + "suffix" for k in data} # {"key1": "value1suffix", "key2": "value2suffix"} +containsKey1 = "key1" in data # True +containsKey2 = "key" in data # False +``` + +#### None + +在 KCL 中, `None` 表示对象的值为空, 这与 Go 中的 `nil` 和 Java 中的 `null` 一样,并且对应于 YAML 中的 `null`。 + +```python +a = None +b = [1, 2, None] +c = {key1 = "value1", key2 = None} +``` + +输出如下: + +```yaml +a: null +b: + - 1 + - 2 + - null +c: + key1: value1 + key2: null +``` + +请注意,`None` 不能参与四则运算,但它可以参与逻辑运算和比较运算。 + +```python +a = 1 + None # error +b = int(None) # error +c = not None # True +d = None == None # True +e = None or 1 # 1 +f = str(None) # None +``` + +#### Undefined + +`Undefined` 与 `None` 类似,但其语义是变量没有分配任何值,也不会输出到 YAML。 + +```python +a = Undefined +b = [1, 2, Undefined] +c = {key1 = "value1", key2 = Undefined} +``` + +输出如下: + +```yaml +b: + - 1 + - 2 +c: + key1: value1 +``` + +请注意,`Undefined` 不能参与四则运算,但它可以参与逻辑运算和比较运算。 + +```python +a = 1 + Undefined # error +b = int(Undefined) # error +c = not Undefined # True +d = Undefined == Undefined # True +e = Undefined or 1 # 1 +f = str(Undefined) # Undefined +``` + +### 运算符 + +以下字符表示运算符: + +```python ++ - * ** / // % +<< >> & | ^ < > +~ <= >= == != @ \ +``` + +#### 算数运算符 + +KCL 支持常见的算数运算符: + +```python +assert 2 + 3 == 5 +assert 2 - 3 == -1 +assert 2 * 3 == 6 +assert 5 / 2 == 2.5 +assert 5 // 2 == 2 +assert 5 % 2 == 1 +``` + +#### 相等和关系运算符 + +KCL 支持相等和关系运算符: + +```python +assert 2 == 2 +assert 2 != 3 +assert 3 > 2 +assert 2 < 3 +assert 3 >= 3 +assert 2 <= 3 +``` + +#### 逻辑运算符 + +我们可以使用逻辑运算符反转或组合布尔表达式,例如:`and` 和 `or`: + +```python +if not done and (col == 0 or col == 3): + # ...Do something... + +``` + +#### 位运算符和移位运算符 + +以下是位运算符和移位运算符的例子: + +```python +value = 0x22 +bitmask = 0x0f + +assert (value & bitmask) == 0x02 +assert (value & ~bitmask) == 0x20 +assert (value | bitmask) == 0x2f +assert (value ^ bitmask) == 0x2d +assert (value << 4) == 0x220 +assert (value >> 4) == 0x02 +``` + +`|` 运算符可用于位运算,合并基本类型和集合及结构化数据,例如**列表**、**字典**和 **schema**。 + +位运算示例: + +```python +0x12345678 | 0xFF # 0x123456FF +``` + +联合基本类型示例: + +```python +schema x: + a: int | str # attribute a could be a int or string +``` + +#### 赋值运算符 + +以下 token 作为语法中的分隔符: + +```txt + ( ) [ ] { } + , : . ; = -> + += -= *= /= //= %= + &= ^= >>= <<= **= +``` + +以下是使用赋值和参数赋值赋值运算符的例子: + +```python +_a = 2 +_a *= 3 +_a += 1 +assert _a == 7 +``` + +#### Identity 运算符 + +以下关键字作为语法中的 identity 运算符: + +```python +is, is not +``` + +Identity 运算符检查右侧和左侧是否时同一对象。它们通常用于检查某个变量是否是 `None/Undefined/True/False`。以下是一些例子: + +```python +empty_String = "" +empty_String is not None # True +``` + +#### 成员运算符 + +以下关键字作为语法中的成员运算符: + +```python +in, not in +``` + +- `in` 运算符计算了第一个操作数是否是第二个操作数的成员,第二个运算符必须是 list、dict、schema 或 string。 +- `not in` 运算符与 `in` 相反。它们都返回一个布尔值。 + +成员的含义因第二个操作数的类型而异:列表的成员是其元素;字典的成员是其键;字符串的成员是其所有子字符串。 + +```python +1 in [1, 2, 3] # True + +d = {one = 1, two = 2} +"one" in d # True +"three" in d # False +1 in d # False +[] in d # False + +"nasty" in "dynasty" # True +"a" in "banana" # True +"f" not in "way" # True + +d = Data {one = 1, two = 2} # Data is a schema with attributes one and two +"one" in d # True +"three" in d # False +``` + +#### 推导式 + +一个推导表达式通过遍历一个或多个迭代项并计算表达式生成的结果来生成连续的元素,并以此构造新的列表或字典。 + +我们可以如下使用列表和字典的推导表达式: + +```python +listVar = [_x for _x in range(20) if _x % 2 == 0] # list comprehension +dictVar = {str(_i): 2*_i for _i in range(3)} # dict comprehension +``` + +#### 其他运算符 + +- 使用 **()** 表示函数调用, 例如 `"{} {}".format("hello", world)`。 +- 使用 **[]** 引用列表中指定索引处的值。 +- 使用 **:** 定义类型注解。 +- 使用 **.** 引用成员字段。 +- 使用 **\\** 续行符编写长表达式。 + +```python +longString = "Too long expression " + \ + "Too long expression " + \ + "Too long expression " +``` + +### 表达式 + +#### 条件表达式 + +条件表达式的形式为 `a if cond else b`。它首先计算条件 `cond`。如果为真,则会计算 `a` 并生成它的值;否则,它会生成 `b` 的值。 + +示例: + +```python +x = True if enabled else False # If enabled is True, x is True, otherwise x is False +``` + +#### 索引表达式 + +索引表达式 `a[i]` 生成可索引类型的第 `i` 个元素,例如字符串或数组。索引 `i` 必须是 `-n` ≤ `i` < `n` 范围内的 `int` 值,其中 `n` 等于 `len(a)`。其他任何索引都会导致错误。 + +有效的负索引的行为类似于 `n+i`,允许方便的对序列末尾进行索引。 + +```python +val = "abc" +list = ["zero", "one", "two"] +str_0 = val[0] # "a" +str_1 = val[1] # "b" +str_n1 = val[-1] # "c" + +list_0 = list[0] # "zero" +list_1 = list[1] # "one" +list_n1 = list[-1] # "two" +``` + +索引表达式 `d[key]` 也可以用于字典 `d`,以获取指定键对应的值。如果字典中不包含这个键则会返回 `Undefined` + +出现在赋值符左侧的索引表达式会更新指定的列表或字典元素。 + +```python +d = {key1 = "value1", key2 = "value2"} +key1value = d["key1"] # value1 +key2value = d["key2"] # value2 +``` + +尝试更新不可变类型的元素值(如列表或字符串)或可变类型的不可变变量会产生错误。 + +#### 切片表达式 + +切片表达式 `a[start:stop:step]` 会生成 `a` 包含的一个子序列,其中 `a` 必须是字符串或者数组。 + +`start`、`stop` 和 `step` 三个操作数都是可选的。如果有的话,每个值都必须为整数。`step` 的默认值为 1。如果 `step` 未指定,它前面的冒号也可以省略。指定 `step` 为 0 会产生错误。 + +从概念上来说,这些操作数指定了一系列值,索引 `i` 从 `start` 开始,每次增加 `step` 直到 `i` 到达或超过 `stop`。结果由有效的 `i` 的 `a[i]` 组成。 + +如下所示,从三个操作数计算有效的开始和结束的索引。`n` 是序列的长度。 + +```python +val = "abc" +len = len(val) +a = val[1:len] # "bc" (remove first element) +b = val[0:-1] # "ab" (remove last element) +c = val[1:-1] # "b" (remove first and last element) +``` + +```python +"abc"[1:] # "bc" (remove first element) +"abc"[:-1] # "ab" (remove last element) +"abc"[1:-1] # "b" (remove first and last element) +"banana"[1::2] # "aaa" (select alternate elements starting at index 1) +"banana"[4::-2] # "nnb" (select alternate elements in reverse, starting at index 4) +``` + +KCL 禁止将切片表达式定义为左值。原因是列表和字符串是不可变的,重新切片可以直接操作操作数,以确保更好的性能。 + +#### 函数调用 + +KCL 允许调用内置函数,或者调用内置和系统模块中的函数。 + +调用函数的基本方法如下所示: + +```python +import math + +a = math.pow(2, 3) # 2 powers 3 is 8. +b = len([1, 2, 3]) # the length of [1, 2, 3] is 3 +``` + +参数以 `,` 分隔,并且 KCL 还支持位置参数和键-值对形式的参数。 + +```python +print("hello world", end="") +``` + +请注意: + +- 有些函数参数具有默认值。 +- 一些函数接受可变参数。 + +如果没有为没有默认值的参数提供参数,则会抛出错误。 + +#### 选择表达式 + +选择表达式选择值的属性或方法。KCL 提供了许多识别或过滤属性的方法: + +`x.y` + +- dict: 表示字典 `x` 中键 `y` 对应的值。 +- schema: 表示 schema `x` 中 `y` 属性的值。 +- package: 表示 package `x` 中 `y` 标示的标识符。 + +示例: + +```python +schema Person: + name: str + age: int + +person = Person { + name = "Alice" + age = 18 +} +name = person.name # "Alice" +age = person.age # 18 + +myDict = { + key = "value" +} +result = myDict.key # "value" +``` + +`x?.y` + +`x` 可以是 schema 实例或 dict。当 `x` 可能为 `None` 或者键 `y` 不在 `x` 中时这非常有用。 + +```python +# Example of dict: +data = {"key" = "value"} +a = data?.key # "value" +b = data?.name # Undefined + +# example of schema instance: +schema Company: + name: str + address: str + +schema Person: + name: str + job?: Company + +alice = Person { + name = "alice" +} + +if alice?.job?.name == "Group": + print("work in Group") +``` + +#### Quantifier 表达式 + +Quantifier 表达式用于集合:列表或字典。通常用于在处理集合后获得某个结果,主要有以下四种形式: + +- **all** + - 用于检测集合中所有元素都满足给定的逻辑表达式,并且返回一个布尔值作为结果。 + - 只有集合中所有元素都满足表达式为 true 时,`all` 表达式为 true,否则为 false。 + - 如果集合为空,返回 true。 + - 支持表达式执行期间逻辑表达式的短路。 +- **any** + - 用于检测集合中至少一个元素都满足给定的逻辑表达式,并且返回一个布尔值作为结果。 + - 当集合中至少一个元素都满足表达式为 true 时,`any` 表达式为 true,否则 false。 + - 如果集合为空,返回 false。 + - 支持表达式执行期间逻辑表达式的短路。 +- **map** + - 映射集合中的元素生成新的列表。 + - 新列表的长度严格等于原列表的长度。 +- **filter** + - 通过逻辑判断筛选原集合中的元素,返回一个经过筛选的子集合。 + - 当表达式为 true 时才将元素添加到子集合。 + - 产生的新集合的类型(list, dict 和 schema)与原集合的类型完全一致,并且长度为 `[0, len(original-collection)]`。 + +**all** 和 **any** 表达式的示例代码: + +```python +schema Config: + volumes: [{str:}] + services: [{str:}] + + check: + all service in services { + service.clusterIP == "NONE" if service.type == "ClusterIP" + }, "invalid cluster ip" + + any volume in volumes { + volume.mountPath in ["/home/admin", "/home/myapp"] + } +``` + +**map** 和 **filter** 表达式的示例代码: + +```python +a = map e in [{name = "1", value = 1}, {name = "2", value = 2}] { + {name = e.name, value = int(e.value) ** 2} +} # [{"name": "1", value: 1}, {"name": "2", "value": 4}] + +b = map k, v in {a = "foo", b = "bar"} { v } # ["foo", "bar"] + +c = filter e in [{name = "1", value = 1}, {name = "2", value = 2}] { + int(e.value) > 1 +} # [{"name": "2", "value": 2}] + +d = filter _, v in {a = "foo", b = "bar"} { + v == "foo" +} # {"a": "foo"} +``` + +请注意,区分 any 表达式和 any 类型的区别。当 `any` 在类型注解中使用,意味着变量的值是任意的,而 any 表达式意味着集合中的至少一个元素满足条件。 + +### 流程控制表达式 + +#### If 和 Else + +KCL 支持 `if` 表达式和可选的 `elif` 和 `else` 表达式, 示例如下: + +```python +a = 10 +if a == 0: + print("a is zero") +elif a < 100: + print("a < 100") + print("maybe a is negative") +else: + print("a >= 100") +``` + +`elif` 的例子: + +```python +_result = 0 +if condition == "one": + _result = 1 +elif condition == "two": + _result = 2 +elif condition == "three": + _result = 3 +else: + _result = 4 +``` + +`if-elif-else` 表达式可以嵌套,示例如下: + +```python +a = 10 +if a == 0: + print("a is zero") +elif a < 100: + print("a < 100") + if a < 0: + print("a is negative") + print("No matter a is negative or positive, this message is printed") +else: + print("a >= 100") +``` + +此外,对于简单的 `if` 表达式如下: + +```python +if success: + _result = "success" +else: + _result = "failed" +``` + +我们可以使用 ` if else ` 的形式将它们写在一行: + +```python +_result = "success" if success else "failed" +``` + +`if` 或 `elif` 语句计算一个给定的表达式。当表达式的计算结果为 `True`, `:` 之后的语句将被计算,而当表达式为 `False` ,后面的语句不会被计算。 + +请注意,常量 `False`, `None`, 数字 `0`, 空列表 `[]`, 空字典 `{}` 和空字符串 `""` 都被视为 `False` 。 + +```python +_emptyStr = "" +_emptyList = [] +_emptyDict = {} +isEmptyStr = False if _emptyStr else True +isEmptyList = False if _emptyList else True +isEmptyDict = False if _emptyDict else True +``` + +结果为: + +```yaml +isEmptyStr: true +isEmptyList: true +isEmptyDict: true +``` + +### 断言语句 + +当发生错误时,开发人员应该能够检测到错误并终止执行。因此,KCL 引入了 `assert` 语法,示例如下: + +```python +a = 1 +b = 3 +# a != b evaluates to True, therefore no error should happen. +assert a != b +# a == b is False, in the reported error message, the message "SOS" should be printed. +assert a == b, "SOS" +``` + +此外,我们可以为 assert 语声明一个条件,当条件满足时,才进行 assert 断言 + +- 使用 if 语句书写条件断言 + +```python +a = None +if a: + assert a > 2: +``` + +- 使用 if 表达式书写条件断言 + +```python +a = None +assert a > 2 if a +``` + +### 函数 + +KCL 支持使用 lambda 关键字定义一个函数 + +```python +func = lambda x: int, y: int -> int { + x + y +} +a = func(1, 1) # 2 +``` + +lambda 函数具有如下特性: + +- lambda 函数将最后一个表达式的值作为函数的返回值,空函数体返回 None +- 返回值类型注解可以省略,返回值类型为最后一个表达式值的类型 +- 函数体中没有与顺序无关的特性,所有的表达式都是按顺序执行的 + +```python +_func = lambda x: int, y: int -> int { + x + y +} # Define a function using the lambda expression +_func = lambda x: int, y: int -> int { + x - y +} # Ok +_func = lambda x: int, y: int -> str { + str(x + y) +} # Error (int, int) -> str can't be assigned to (int, int) -> int +``` + +lambda 函数对象不能参与任何计算,只能在赋值语句和调用语句中使用。 + +```python +func = lambda x: int, y: int -> int { + x + y +} +x = func + 1 # Error: unsupported operand type(s) for +: 'function' and 'int(1)' +``` + +lambda 函数支持捕获其外部作用域的变量,并且可以作为其他函数的参数进行传递 + +```python +a = 1 +func = lambda x: int { + x + a +} +funcOther = lambda f, para: int { + f(para) +} +r0 = funcOther(func, 1) # 2 +r1 = funcOther(lambda x: int { + x + a +}, 1) # 2 +``` + +输出为: + +```yaml +a: 1 +r: 2 +``` + +此外,可以定义一个匿名函数并直接调用。 + +```python +result = (lambda x, y { + z = 2 * x + z + y +})(1, 1) # 3 +``` + +并且还可以在 for 循环使用使用匿名函数 + +```python +result = [(lambda x, y { + x + y +})(x, y) for x in [1, 2] for y in [1, 2]] # [2, 3, 3, 4] +``` + +请注意,KCL 中定义的函数的均为纯函数: + +- 函数的返回结果只依赖于它的参数。 +- 函数执行过程里面没有副作用。 + +因此,KCL 函数不能修改外部的变量,只能引用外部的变量,比如如下代码会发生错误: + +```python +globalVar = 1 +func = lambda { + x = globalVar # Ok + globalVar = 1 # Error +} +``` + +### 类型系统 + +#### 类型注解 + +类型注解可用于包级变量,schema 属性和参数。 + +- 属性可以是基本类型,例如字符串(`string`),浮点数(`float`),定点数(`int`) 或布尔值(`bool`)。 +- 属性可以是字面值类型,例如字符串文本(`"TCP"` 和 `"UDP"`),数字文本 (`"1"` 和 `"1.2"`),布尔值文本(`True` 和 `False`)。 +- 属性也可以是列表或字典: + - 未指定元素类型的列表为 `[]`。 + - 元素类型为 `t` 的列表为 `[t]`。这里 `t` 是另一种类型。 + - 键的类型为 `kt` 且值的类型为 `vt` 的字典为 `{kt:vt}`。 + - `kt`, `vt` 或两者都可以为空, 就像列表未指定元素类型一样。 +- 属性可以是由 `|` 定义的 **联合类型** ,例如 `a | b`, 意为类型可以是 a 或 b。 + - 联合类型可以包含 `int`, `str`, `float`, `bool`, `list`, `dict`, 字面值类型和 schema 类型,并且支持类型的嵌套,例如: `{str:str|int}`、`[[int|str]|str|float]` 和 `2 | 4 | 6` 等。 +- 属性可以是 schema 类型。在这种情况下,使用包名 + schema 名称作为类型名。 +- 属性可以声明为任意类型,例如 `any`。 + +示例 + +- 基本类型 + +```python +"""Top level variable type annotation""" +a: int = 1 # Declare a variable `a` that has the type `int` and the value `1` +b: str = "s" # Declare a variable `b` that has the type `str` and the value `"s"` +c: float = 1.0 # Declare a variable `c` that has the type `float` and the value `1.0` +d: bool = True # Declare a variable `d` that has the type `bool` and the value `True` +``` + +- List/Dict/Schema 类型 + +```python +schema Person: + name: str = "Alice" + age: int = 10 + +a: [int] = [1, 2, 3] # Declare a variable `a` that has the list type `[int]` and the value `[1, 2, 3]` +b: {str:str} = {k1 = "v1", k2 = "v2"} # Declare a variable `b` that has the dict type `{str:str}` and the value `{k1 = "v1", k2 = "v2"}` +c: Person = Person {} # Declare a variable `c` that has the schema type `Person` and the value `Person {}` +``` + +- 联合类型 + +```python +# Basic union types +schema x[argc: int]: # Schema argument type annotation + p: int | str # Schema attribute type annotation +``` + +```python +# Literal union types +schema LiteralType: + # String literal union types, x_01 can be one of "TCP" and "UDP" + x_01: "TCP" | "UDP" + # Number literal union types, x_02 can be one of 2, 4, and 6 + x_02: 2 | 4 | 6 + # Unit union types, x_03 can be one of 1Gi, 2Gi and 4Gi + x_03: 1Gi | 2Gi | 4Gi + +x = LiteralType { + x_01 = "TCP" + x_02 = 2 + x_03 = 1Gi +} +``` + +当属性的值不符合联合类型定义时,编译器会抛出错误: + +```python +# Literal union types +schema LiteralType: + # String literal union types, x_01 can be one of "TCP" and "UDP" + x_01: "TCP" | "UDP" + +x = LiteralType { + x_01 = "HTTP" # Error: the type got is inconsistent with the type expected, expect str(TCP)|str(UDP), got str(HTTP) +} +``` + +- Any 类型 + +```python +# Any type +schema Config: + literalConf: any = 1 + dictConf: {str:any} = {key = "value"} + listConf: [any] = [1, "2", True] + +config = Config {} +``` + +请注意,一般在配置编写中不提倡使用 `float` 和 `any` 类型,因为它们都存在一定的不稳定因素,比如精度丢失,无法进行静态类型检查等。 + +此外在 KCL 中,不允许修改一个变量的类型。如果在重新分配值时不满足类型,将引发类型错误。 + +```python +_a = 1 # The type of `_a` is `int` +_a = "s" # Error: expect int, got str(s) +``` + +变量可以赋值给其上界类型,但不能赋值给它的特化类型。 + +`None` 和 `Undefined` 可以赋值给任何类型: + +- 任何类型都可以赋值给 `any` 类型, `None` 和 `Undefined` 可以赋值给 `any` 类型。 + +```python +a: int = None +b: str = Undefined +c: any = 1 +d: any = "s" +e: any = None +``` + +- `int` 类型可以赋值给 `float` 类型, `float` 类型不能赋值给 `int` 类型. + +```python +a: float = 1 +b: int = 1.0 # Error: expect int, got float(1.0) +``` + +- `int` 类型可以赋值给 `int|str` 类型, `int|str` 不能赋值给 `int` 类型. + +```python +a: int | str = 1 +b: int = 1 if a else "s" # Error: expect int, got int(1)|str(s) +``` + +请注意,在 KCL 中虽然提供了 any 类型,但是它仍然是静态类型,所有变量的类型在编译期间不可变。 + +#### 类型推导 + +如果顶层或 schema 中的变量或常量声明没有使用显式的类型注解,则会从初始值推断类型。 + +- 整形数值被推断为 `int`。 + +```python +a = 1 # The variable `a` has the type `int` +``` + +- 浮点数被推断为 `float`。 + +```python +a = 1.0 # The variable `a` has the type `float` +``` + +- 字符串被推断为 `str`。 + +```python +a = "s" # The variable `a` has the type `str` +``` + +- 布尔值被推断为 `bool`。 + +```python +a = True # The variable `a` has the type `bool` +b = False # The variable `b` has the type `bool` +``` + +- `None` 和 `Undefined` 被推断为 `any`。 + +```python +a = None # The variable `a` has the type `any` +b = Undefined # The variable `b` has the type `any` +``` + +- 列表的类型根据元素类型推断,并且是可变大小的。 + +```python +a = [1, 2, 3] # The variable `a` has the type `[int]` +b = [1, 2, True] # The variable `b` has the list union type `[int|bool]` +c = ["s", 1] # The variable `c` has the list union type `[int|str]` +``` + +请注意,空列表将被推导为 `[any]` 类型。 + +```python +a = [] # The variable `a` has the type `[any]` +``` + +- 字典的类型是根据元素的键和值推断的,并且是可变大小的。 + +```python +a = {key = "value"} # The variable `a` has the type `{str:str}` +b = {key = 1} # The variable `b` has the type `{str:int}` +c = {key1 = 1, key2 = "s"} # The variable `c` has the type `{str:int|str}` +``` + +请注意,空字典将被推导为 `{any:any}` 类型。 + +```python +a = {} # The variable `a` has the type `{any:any}` +``` + +- 携带运行时值的 if 条件表达式的类型将被静态推断为所有可能结果的联合类型。 + +```python +a: bool = True # The variable `a` has the type `bool` +b = 1 if a else "s" # The variable `b` has the type `int|str` +``` + +当变量被推导为某个类型时,它的类型不能再改变。 + +```python +_a = 1 +_a = "s" # Error: expect int, got str(1) +``` + +#### 类型别名 + +在 KCL 中,我们可以使用 `type` 关键字为所有类型声明一个类型别名简化复杂类型的书写。 + +```python +type Int = int +type String = str +type StringOrInt = String | Int +type IntList = [int] +type StringAnyDict = {str:} +``` + +我们可以从一个包中导入一个类型并为它定义一个别名。 + +```py +import pkg + +type Data = pkg.Data +``` + +此外,我们还可以使用类型别名和字面值联合类型充当近似枚举的效果。 + +```python +# A type alias of string literal union types +type Color = "Red" | "Yellow" | "Blue" + +schema Config: + color: Color = "Red" # The type of color is `"Red" | "Yellow" | "Blue"`, and it has an alias `Color`, whose default value is `"Red"` + +config = Config { + color = "Blue" +} +``` + +上述代码执行的输出结果为: + +```yaml +config: + color: Blue +``` + +请注意,类型别名不能与已有的内置类型 `any`、`int`、`float`、`bool` 和 `str` 等相同 + +```python +type any = int | str # Error +type int = str # Error +type float = int # Error +type bool = True # Error +type str = "A" | "B" | "C" # Error +``` + +#### 类型守卫 + +KCL 支持在程序中使用 `typeof` 函数对任意值求得其运行时的类型。 + +```python +import sub as pkg + +_a = 1 + +t1 = typeof(_a) +t2 = typeof("abc") + +schema Person: + name?: any + +_x1 = Person {} +t3 = typeof(_x1) + +_x2 = pkg.Person {} +t4 = typeof(_x2) +t5 = typeof(_x2, full_name=True) + +t6 = typeof(_x1, full_name=True) + +# Output +# t1: int +# t2: str +# t3: Person +# t4: Person +# t5: sub.Person +# t6: __main__.Person +``` + +除此之外,我们可以使用 `as` 关键字在运行时作类型转换。`as` 关键字的一般用法如下: + +- 具有偏序关系的基础类型,比如 `float -> int` +- 具有偏序关系的联合类型,比如 `int | str -> str` +- 对类型上界 `any` 的转换,比如 `any -> int` +- 具有偏序关系的结构类型,比如 `base-schema -> sub-schema` + +```python +schema Data1: + id?: int + +schema Data2: + name?: str + +data: Data1 | Data2 = Data1 {} + +if typeof(data) == "Data1": + data1 = data as Data1 # The type of `data` is `Data1` +elif typeof(data) == "Data2": + data2 = data as Data2 # The type of `data` is `Data2` +``` + +当类型转换失败时,一个运行时错误将被抛出。 + +```python +a: any = "s" +b: int = a as int # Error: The `str` type cannot be converted to the `int` type +``` + +如果不想要运行时类型转换失败,我们可以添加 `if` 防御式代码进行检查。 + +```python +a: any = "s" +b = a as int if typeof(a) == "int" else None # The type of b is `int` +``` + +请注意,`as` 转换的目标类型不能是字面值类型或者联合类型,因为它们在运行时不具有一个完全确定的类型。 + +### Schema + +#### 概述 + +Schema 是定义复杂配置的语言元素。我们可以定义带类型的属性,初始值和验证规则。此外,KCL 支持 schema 单继承、mixin 和 protocol 实现复杂配置的复用。 + +#### 基础部分 + +##### 属性 + +以下是 schema 基础定义的示例: + +```python +# A person has a first name, a last name and an age. +schema Person: + firstName: str + lastName: str + # The default value of age is 0 + age: int = 0 +``` + +在 KCL 中, 我们可以使用类型注解在 schema 中定义一些属性,每个属性都可以设置一个可选的默认值(比如上述代码中的 `age` 属性,它的默认值是 `0`),没有设置默认值的属性的初始值为 `Undefined`, 它们不会在 YAML 当中进行输出。 + +###### 不可变性 + +schema 中属性的不可变性遵循和全局变量不可变性一样的规则,只有 schema 中的可变属性可以在 schema 中修改。此外,schema 的属性默认值可被 schema 配置值修改: + +```python +schema Person: + age: int = 1 # Immutable attribute + _name: str = "Alice" # Mutable attribute + + age = 10 # Error, can't change the default value of the attribute `age` in the schema context. + _name = "Bob" # Ok + +person = Person { + age = 3 # Ok, can change the default value of the attribute `age` in the schema config. +} +``` + +###### 可选属性 + +schema 实例中每个属性 **必须** 赋值一个非 `None`/`Undefined` 的值,否则编译器会抛出错误,除非它被 `?` 符号标记为可选属性。 + +示例: + +```python +schema Employee: + bankCard: int # bankCard is a required attribute, and it can NOT be None or Undefined + nationality?: str # nationality is an optional attribute, and it can be None or Undefined + +employee = Employee { + bankCard = None # Error, attribute 'bankCard' of Employee is required and can't be None or Undefined + nationality = None # Ok +} +``` + +##### 顺序无关计算 + +schema 中顺序无关计算表示 schema 内部属性之间的引用关系。例如,当我们声明一个形式为 `a = b + 1` 的表达式时,`a` 值的计算依赖于 `b` 值的计算。当编译器计算 `a` 的值并且 `a` 的值取决于 `b` 的值时,编译器会选择先计算 `b` 的值,然后根据 `b` 的值计算 a 的值表达式 `a = b + 1`,这与传统过程语言的计算方法略有不同。 + +由于 schema 中值的计算是基于依赖关系的,就像有向无环图按照拓扑排序的顺序遍历图中的每个节点一样, schema 中属性的声明顺序并不那么重要,因此特征称为顺序无关计算。 + +请注意,不同 schema 属性值之间不能有循环引用。 + +我们可以通过下面的例子看到这个特性。 + +```python +schema Fib: + n1: int = n - 1 # Refers to the attribute `n` declared after `n1` + n2: int = n1 - 1 + n: int + value: int = 1 if n <= 2 else Fib {n = n1}.value + Fib {n = n2}.value + +fib8 = Fib {n = 8}.value +``` + +结果为: + +```yaml +fib8: 21 +``` + +在 schema 中,我们只需要简单的指定属性之间的依赖关系,编译器就会根据依赖关系自动计算出值,这样可以帮助我们节省大量的样板代码,减少配置编写难度。 + +##### Schema 上下文 + +我们可以定义 schema 的上下文来管理 schema 的属性,可以直接在 schema 中编写 schema 参数、临时变量和表达式等: + +```python +schema Person[_name: str]: # define a schema argument + name: str = _name # define a schema attribute + age: int = 10 # define a schema attribute with default value + hands: [int] = [i for i in [1, 2, 3]] # define a for statement +``` + +然后,我们可以通过如下代码实例化一个 `Person` 并将其赋值给 `alice` 变量: + +```python +alice = Person("alice") +``` + +可以得到如下 YAML 输出: + +```yaml +alice: + name: alice + age: 10 + hands: + - 1 + - 2 + - 3 +``` + +##### 校验 + +KCL 中为了确保代码稳定性,除了使用 **静态类型** (类型注解) 和 **不可变性**,还支持在 **check** 块中定义验证规则 (KCL 几乎原生支持所有 [OpenAPI](https://www.openapis.org/) 的验证能力): + +```python +import regex + +schema Sample: + foo: str + bar: int + fooList: [str] + + check: + bar > 0 # Minimum, also support the exclusive case + bar < 100 # Maximum, also support the exclusive case + len(fooList) > 0 # Min length, also support exclusive case + len(fooList) < 100 # Max length, also support exclusive case + regex.match(foo, "^The.*Foo$") # Regex match + isunique(fooList) # Unique + bar in range(100) # Range + bar in [2, 4, 6, 8] # Enum + multiplyof(bar, 2) # MultipleOf +``` + +使用 schema, 所有的实例将在编译时验证: + +```python +# Ok +goodSample = Sample { + foo = "The Foo" + bar = 2 + fooList = ["foo0", "foo1"] +} + +# Error: validation failure: Check failed on check conditions: bar < 100. +badSample = Sample { + foo = "The Foo" + bar = 123 + fooList = ["foo0", "foo1"] +} +``` + +此外,我们可以使用 **and**, **or**, **if** 来构建更复杂的检查逻辑: + +```python +schema Sample: + bar: int + foo: str + doCheck: bool + + check: + regex.match(foo, "^The.*Foo$") and bar in [2, 4, 6, 8] if doCheck +``` + +为了确保所有检查规则都能很好地发挥其相应的作用,我们可以通过编写 KCL 测试用例来测试不同数据组合的合理性和正确性,并通过 kcl test tool 运行所有测试用例。 + +##### 文档 + +通常在我们写好 schema 模型之后,我们会为 schema 写文档注释,可以用一个三引号字符串来完成,如下所示: + +```python +schema Server: + """Server is the common user interface for long-running + services adopting the best practice of Kubernetes. + + Attributes + ---------- + workloadType : str, default is Deployment + Use this attribute to specify which kind of long-running service you want. + Valid values: Deployment, CafeDeployment. + See also: k8s/core/v1/workload_metadata.k. + name : str, default is None + A Server-level attribute. + The name of the long-running service. + See also: k8s/core/v1/metadata.k. + labels : {str:str}, optional, default is None + A Server-level attribute. + The labels of the long-running service. + See also: k8s/core/v1/metadata.k. + + Examples + ---------------------- + myCustomApp = AppConfiguration { + name = "componentName" + } + """ + workloadType: str = "Deployment" + name: str + labels?: {str:str} +``` + +更多详细内容可见 Doc tools。 + +##### 配置 + +假设我们有如下 schema 定义: + +```python +schema Person: + firstName: str + lastName: str + labels?: {str:str} +``` + +可以用类 JSON 的表达式定义配置: + +```python +person = Person { + firstName = "firstName" + lastName = "lastName" +} +``` + +schema 遵循严格的属性定义,配置未定义的属性将触发编译错误: + +```python +person = Person { + firstName = "firstName" + lastName = "lastName" + fullName = "fullName" # Error: Cannot add member 'fullName' to schema 'Person', 'fullName' is not defined in schema 'Person' +} +``` + +此外,我们可以使用 `if` 表达式将元素动态的添加到 schema 实例中,将满足条件的元素添加到 schema 实例并忽略不满足条件的元素。并且除了使用一个 schema 类型实例化一个 schema,我们也可以通过 schema 实例得到一个新的实例。 + +```python +env = "prod" +person = Person { + firstName = "firstName" + lastName = "lastName" + if env == "prod": + labels.env = env + else: + labels.env = "other" +} +# We can use the person instance to get a new instance named `personx` directly. +personx = person { + firstName = "NewFirstName" +} +``` + +输出为: + +```yaml +env: prod +person: + firstName: firstName + lastName: lastName + labels: + env: prod +personx: + firstName: NewFirstName + lastName: lastName + labels: + env: prod +``` + +#### 高级功能 + +##### Protocol & Mixin + +除了 schema, 在 KCL 中还提供了一种额外的类型定义方式 `protocol`,它的性质如下: + +- 在 protocol 中,只能定义属性及其类型,不能书写复杂的逻辑与 check 表达式,也不能使用 mixin。 +- protocol 只能对非 `_` 开头的属性进行约束。 +- protocol 只能继承自或者引用 protocol, 不能继承自或者引用 schema。 + +此外,我们可以使用可选的 **mixin** 组装复杂的 schema,并使用 **protocol** 为 **mixin** 添加可选的宿主类型, 使用 `for` 关键字为 **mixin** 定义宿主类型,并且在 mixin 内部它将从宿主类型中查询到属性的类型。 + +```python +schema Person: + mixin [FullNameMixin] + + firstName: str # Required + lastName: str # Required + fullName?: str # Optional +``` + +FullNameMixin 是一个产生 fullName 字段的简单例子: + +```python +protocol PersonProtocol: + firstName: str + lastName: str + fullName?: str + +mixin FullNameMixin for PersonProtocol: + fullName = "{} {}".format(firstName, lastName) +``` + +然后我们可以通过一下方式获取 schema 实例: + +```python +person = Person { + firstName = "John" + lastName = "Doe" +} +``` + +输出结果为: + +```yaml +person: + firstName: John + lastName: Doe + fullName: John Doe +``` + +请注意,宿主类型 **protocol** 只能用于 **mixin** 的定义 (后缀名为 `Mixin`), 否则将会报错。 + +```python +protocol DataProtocol: + data: str + +schema Data for DataProtocol: # Error: only schema mixin can inherit from protocol + x: str = data +``` + +##### 索引签名 + +在 KCL schema 中可以定义索引签名,这意味着索引签名的键-值约束可用于构造具有 schema 类型的字典。或者可以将其他检查添加到额外的 schema 属性中,以增强 KCL 类型和语义检查。 + +###### 基本用法 + +使用 `[{attr_alias}: {key_type}]: {value_type}` 的形式去定义 schema 的类型注解, 其中 `{attr_alias}` 可以省略。 + +```python +schema Map: + """ + Map is a schema with a key of str type and a value of str type + """ + [str]: str # `{attr_alias}` can be omitted. + +data = Map { + key1 = "value1" + key2 = "value2" +} +``` + +###### 同时定义属性和索引签名 + +可以在 schema 中同时定义 schema 属性和索引签名,通常用于表示 schema 中额外属性的类型约束,比如如下代码 + +```python +schema Person: + name: str + age: int + [...str]: str # Except for the `name` and `age` attributes, the key type of all other attributes of the schema must be `str`, and the value type must also be `str`. +``` + +###### 定义索引签名别名 + +- 可以为索引签名定义类型注解的属性别名,并将其与索引签名的默认值一起使用。 + +```python +schema Environment: + [id: str]: EnvironmentSpec = { + fullName = id + } + +schema EnvironmentSpec: + fullName: str + shortName: str = fullName + accountID: int + +environment = Environment { + development: { + shortName: "dev" + accountID: 123456 + } + production: { + shortName: "prod" + accountID: 456789 + } +} +``` + +YAML 输出为: + +```yaml +environment: + production: + fullName: production + shortName: prod + accountID: 456789 + development: + fullName: development + shortName: dev + accountID: 123456 +``` + +- 可以为索引签名定义类型注解的属性别名,并将其与检查块一起使用。 + +```python +schema Data: + [dataName: str]: str + check: + dataName in ["Alice", "Bob", "John"] # We can use the index signature key name in the check block. + +data = Data { + Alice = "10" + Bob = "12" + Jonn = "8" # Error: Jonn not in ["Alice", "Bob", "John"] +} +``` + +```python +import regex + +schema DataMap: + [attr: str]: str + check: + regex.match(attr, r'^[-_a-zA-Z0-9]+$') + +data = DataMap { + key1 = "value1" + "foo.bar" = "value2" # check error +} +``` + +##### 继承 + +类似于其他面向对象语言,KCL 提供了基础且有限的面向对象支持,例如 **属性复用**,**私有和公有变量**和**单继承**。KCL 不支持多继承。 + +以下是单继承的例子: + +```python +# A person has a first name, a last name and an age. +schema Person: + firstName: str + lastName: str + # The default value of age is 0 + age: int = 0 + +# An employee **is** a person, and has some additional information. +schema Employee(Person): + bankCard: int + nationality?: str + +employee = Employee { + firstName = "Bob" + lastName = "Green" + age = 18 + bankCard = 123456 +} +``` + +结果为: + +```yaml +employee: + firstName: Bob + lastName: Green + age: 18 + bankCard: 123456 + nationality: null +``` + +请注意,KCL 只支持 schema 的 **单继承**。 + +此外,当 schema 存在继承关系时,可选属性的性质如下: + +- 如果该属性在基类 schema 中是可选的,则它在子类 schema 中是可选的,也可以是子类 schema 中必选的。 +- 如果该属性在基类 schema 中是必选的,则它在子类 schema 中也是必选的。 + +```python +schema Person: + bankCard?: int + nationality: str + +schema Employee(Person): + bankCard: int # Valid, both `bankCard: int` and `bankCard?: int` are allowed + nationality?: str # Error, only `nationality: str` is allowed +``` + +##### Schema 函数 + +schema 映射到函数上非常好用;它可以有任意数量的输入和输出参数。 例如,Fibonacci 函数可以使用递归 schema 如下编写: + +```python +schema Fib[n: int]: + n1 = n - 1 + n2 = n - 2 + if n == 0: + value = 0 + elif n == 1: + value = 1 + else: + value = Fib(n1).value + Fib(n2).value + +fib8 = Fib(8).value # 21 +``` + +##### 装饰器 + +像 Python 一样, KCL 支持在 schema 上使用装饰器。KCL 装饰器动态地改变 schema 的功能,而不必直接使用子 schema 或更改被装饰的 schema 的源代码。 和函数调用一样,装饰器支持传入额外的参数。 + +内置的 schema 装饰器: + +- `@deprecated` + 标识 schema 或 schema 属性被废弃. `@deprecated` 装饰器支持三种参数: + - **version** - 字符串类型,表示版本信息。 默认值为空。 + - **reason** - 字符串类型,表示不推荐使用的原因。 默认值为空。 + - **strict** - bool 类型,表示是报错还是警告。 默认值是 true。 如果 `strict` 为 `True` 并且抛出错误,程序将被中断。 如果 `strict` 为 `False`,则会输出警告并且不会中断程序。 + +示例: + +```python +@deprecated +schema ObsoleteSchema: + attr: str + +schema Person: + firstName: str = "John" + lastName: str + @deprecated(version="1.16", reason="use firstName and lastName instead", strict=True) + name: str + attrs: ObsoleteSchema = { # Error: ObsoleteSchema was deprecated + attr = "value" + } + +JohnDoe = Person { # Error: name was deprecated since version 1.16, use firstName and lastName instead + name = "deprecated" +} +``` + +- `@info` + 给 schema 或 schema 属性标识额外的信息,支持任意参数,用于语言静态分析 schema 或 schema 属性的扩展标记信息 + +示例: + +```python +@info(version="v1") +schema Person: + @info(message="name") + name: str + age: int +``` + +请注意,当前版本的 KCL 尚不支持用户自己定义装饰器。 + +##### 成员函数 + +内置函数和 schema 成员 + +- instances(full_pkg: bool = False) + 返回 schema 的现有实例列表,当 `full_pkg` 设置为 `False` 时,仅返回 main 中的 schema 实例,当 `full_pkg` 设置为 `True` 时,返回整个项目对应 schema 的所有实例。 + +```python +schema Person: + name: str + age: int + +alice = Person { + name = "Alice" + age = 18 +} + +bob = Person { + name = "Bob" + age = 10 +} + +aliceAndBob = Person.instances() # Person is a schema type, instances() is its member method +``` + +输出为: + +```yaml +alice: + name: Alice + age: 18 +bob: + name: Bob + age: 10 +aliceAndBob: + - name: Alice + age: 18 + - name: Bob + age: 10 +``` + +### 配置操作 + +#### 配置合并 + +##### | 运算符 + +在 KCL 中,我们可以使用合并运算符 `|` 来合并配置。union 运算符支持的类型包括如下: + +```txt +SchemaInstance | SchemaInstance +SchemaInstance | Dict +Dict | Dict +List | List +``` + +合并集合和结构化数据: + +- 合并 List。使用 `|` 运算符右边的列表表达式按照**索引**逐一覆盖左边列表表达式中的元素。 + +```python +_a = [1, 2, 3] +_b = [4, 5, 6, 7] +x = _a | _b # [4, 5, 6, 7] 1 -> 4; 2 -> 5; 3 -> 6; Undefined -> 7 +``` + +合并特定索引或所有元素仍在讨论中。 + +- 合并 Dict. 使用 `|` 运算符右边的列表表达式按照**键**逐一覆盖左边列表表达式中的元素。 + +```python +_a = {key1 = "value1"} +_b = {key1 = "overwrite", key2 = "value2"} +x = _a | _b # {"key1": "overwrite", "key2": "value2"} +``` + +集合和 schema 的合并是一个新的集合,其属性是将 b 合并到 a,保留从左到右的操作数顺序。 + +- 合并 schema。Schema 的合并与 dict 相似。 + +Schema 的合并操作如下: + +```python +schema Person: + firstName?: str + lastName?: str + +_a = Person { + firstName = "John" +} +_b = {lastName = "Doe"} +_c = _a | _b # {"firstName": "John", "lastName": "Doe"} +_d = _a | None # {"firstName": "John"} +_e = _a | Undefined # {"firstName": "John"} +_f = None | _a # {"firstName": "John"} +_g = Undefined | _a # {"firstName": "John"} +``` + +请注意,当 union 运算符的左右操作数之一为 None 时,将立即返回另一个操作数。 + +```python +data1 = {key = "value"} | None # {"key": "value"} +data2 = None | [1, 2, 3] # [1, 2, 3] +data3 = None | None # None +``` + +输出如下: + +```yaml +data1: + key: value +data2: + - 1 + - 2 + - 3 +data3: null +``` + +##### : 运算符 + +模式: `identifier : E` + +表达式 `E` 的值将被合并到元素值。 + +示例: + +```python +schema Data: + labels: {str:} = {key1 = "value1"} + +data = Data { + # union {key2: "value2"} into the attribute labels of the schema Data. + labels: {key2 = "value2"} +} +``` + +输出: + +```yaml +data: + labels: + key1: value1 + key2: value2 +``` + +除了在 schema 属性上使用属性运算符之外,还可以使用属性运算符对配置块执行不同的操作。 + +- schema 外部使用合并运算符 `:` + +```python +schema Data: + d1?: int + d2?: int + +schema Config: + data: Data + +# This is one configuration that will be merged. +config: Config { + data.d1 = 1 +} +# This is another configuration that will be merged. +config: Config { + data.d2 = 2 +} +``` + +与它等效的配置代码可以表示为: + +```python +schema Data: + d1?: int + d2?: int + +schema Config: + data: Data + +config: Config { + data.d1 = 1 + data.d2 = 1 +} +``` + +输出结果为: + +```yaml +config: + data: + d1: 1 + d2: 1 +``` + +- schema 内部使用合并运算符 `:` + +```python +schema Data: + d1?: int + d2?: int + +schema Config: + # This is one configuration that will be merged. + data: Data { + d1 = 1 + } + # This is another configuration that will be merged. + data: Data { + d2 = 1 + } + +config: Config {} +``` + +#### 配置覆盖 + +##### = 运算符 + +模式: `identifier = E` + +表达式 `E` 的值将覆盖元素值。 + +示例: + +```python +schema Data: + labels: {str:} = {key1 = "value1"} + +data = Data { + # override {key2: "value2"} into the attribute labels of the schema Data. + labels = {key2 = "value2"} +} +``` + +输出: + +```yaml +data: + labels: + key2: value2 +``` + +请注意,可以使用 `Undefined` 来覆盖,来“删除”内容。例如 `{ a = Undefined }`。 + +#### 配置添加 + +##### += 运算符 + +模式: `identifier += E` + +插入只能用于列表类型的 `identifier`. + +`E` 将插入到列表 `identifier` 指定索引后,并且索引以后的属性将自动后移。 + +示例: + +```python +schema Data: + labels: {str:} = {key1 = [0, 1, 3]} + +data = Data { + # insert [3] after the index 1 of the attribute labels.key1 of the schema Data. + labels: {key1[1] += [2]} +} +``` + +输出: + +```yaml +data: + labels: + key1: + - 0 + - 1 + - 2 + - 3 +``` + +如果没有定义索引,将使用最后一个索引。 + +#### 注意事项 + +合并运算符 `:` 是一个可交换的幂等运算符,当合并的值发生值的冲突时会发生值冲突错误,因此我们需要 `=` 和 `+=` 运算符表示配置的覆盖,添加和删除操作。 + +```python +data0 = {id: 1} | {id: 2} # Error:conflicting values between {'id': 2} and {'id': 1} +data1 = {id: 1} | {id = 2} # Ok, the value of `data` is {"id": 2} +``` + +`:` 运算符冲突检查的规则如下: + +- `None` 和 `Undefined` 不与任何值冲突 + +```python +data0 = None | {id: 1} # Ok +``` + +- 对于 `int`、`float`、`str` 和 `bool` 类型的变量,当它们的值不相同时发生冲突错误。 + +```python +data0 = 1 | 1 # Ok +data1 = 1 | "s" # Error +``` + +- 对于列表类型 + - 当它们的长度不相同时,它们被认为是冲突的 + - 当它们的长度相同时,当且仅当它们的任意一个子元素值冲突时,它们自身是冲突的 + +```python +data0 = [1] | [1] # Ok +data1 = [1, 2] | [1] # Error +``` + +- 对于 dict/schema 类型 + - 对于相同的 key,key 的值冲突时,它们自身是冲突的,否则是不冲突的 + +```python +data0 = {id: 1} | {id: 1} # Ok +data1 = {id: 1} | {id: 2} # Error +data1 = {id: 1} | {idAnother: 1} # Ok +``` + +### Rule + +KCL 支持使用 rule 关键字定义校验块,可用于数据校验,用法类似于 schema 中的 check 表达式。 + +```python +rule SomeRule: + age > 0, "rule check failure message" +``` + +可以像 schema 实例化那样调用一个 rule 进行校验 + +```python +age = 0 +name = "Bob" +rule SomeRule: + age > 0, "rule check failure message" + name == "Alice" + +rule1 = SomeRule() # Rule call +rule2 = SomeRule {} +``` + +可以使用 protocol 和 for 绑定语句为 rule 增加类型约束: + +```python +# Protocol definition +protocol ServiceProtocol: + clusterIp: str + $type: str + +# Protocol definition +protocol VolumeProtocol: + mountPath: str + +# Protocol +protocol SomeProtocol: + id: int + env: {str: any} + services: [ServiceProtocol] + volumes: [VolumeProtocol] + +rule SomeChecker for SomeProtocol: + id > 0, "id must >0" + + all service in services { + service.clusterIp == "NONE" if service.type == "ClusterIP" + } + + any volume in volumes { + volume.mountPath in ["/home/admin", "/home/myapp"] + } + +# Call rule to check with config parameter +SomeChecker { + id = 1 + env = { + MY_ENV = "MY_ENV_VALUE" + } + services = [ + { + type = "ClusterIP" + clusterIp = "NONE" + } + ] + volumes = [ + { + mountPath = "/home/admin" + } + { + mountPath = "/home/myapp" + } + ] +} +``` + +请注意,`protocol` 和 `rule` 的组合方式可以使属性和其约束定义进行分离,我们可以在不同的包中定义不同的 `rule` 和 `protocol` 按需进行组合,这与 schema 中的 check 表达式只能与 schema 属性定义在一起是不同的。 + +此外,有两种复用不同 rule 的方式 + +- 直接调用 + +```python +weather = "sunny" +day = "wednesday" + +rule IsSunny: + weather == "sunny" + +rule IsWednesday: + day == "wednesday" + +rule Main: + IsSunny() # Rule inline call + IsWednesday() # Rule inline call + +Main() # Rule call +``` + +使用 rule 的继承 (rule 不同于 schema, 可以多继承混用) + +```python +weather = "sunny" +day = "wednesday" + +rule IsSunny: + weather == "sunny" + +rule IsWednesday: + day == "wednesday" + +rule Main(IsSunny, IsWednesday): + id == 1 + +Main() +``` + +可以使用 option 函数与命令行 `-D` 参数获得外部数据进行校验 + +- 一个简单例子 + +```python +schema Day: + day: str + homework: str + +days: [Day] = option("days") + +rule Main: + filter d in days { + d.day not in ["saturday", "sunday"] and d.homework + } + +Main() +``` + +- 一个复杂例子 + +```python +data = option("data") +input = option("input") + +rule Allow: + UserIsAdmin() + any grant in UserIsGranted() { + input.action == grant.action and input.type == grant.type + } + +rule UserIsAdmin: + any user in data.user_roles[input.user] { + user == "admin" + } + +rule UserIsGranted: + [ + grant + for role in data.user_roles[input.user] + for grant in data.role_grants[role] + ] + +allow = Allow() or False +``` + +### 模块 + +KCL 配置文件以 **模块 (module)** 形式组织。 单个 KCL 文件被认为是一个模块,一个目录被认为是一个包。 + +同一个包内的模块是可见的,跨包引用需要通过导入可见。 + +```bash +. +└── root + ├── model + │ ├── model1.k + | ├── model2.k + │ └── main.k + ├── service + │ └── service1.k + └── mixin + └── mixin1.k +``` + +model1.k: + +```python +# schema CatalogItem in model1.k + +schema CatalogItem: + id: int + image: CatalogItemImage # CatalogItemImage is defined in the module of the same package e.g., model2.k in package model + title: str +``` + +service1.k: + +```python +import ..model as model # cross-package references + +schema ImageService: + image: model.CatalogItemImage # CatalogItemImage is imported from another package e.g., model2.k in package model + name: str +``` + +#### 相对路径引用 + +我们可以使用 `.` 运算符来实现 KCL 入口文件的相对路径导入。 + +main.k: + +```python +import .model1 # Current directory module +import ..service # Parent directory +import ...root # Parent of parent directory + +s = service.ImageService {} +m = root.Schema {} +``` + +#### 绝对路径引用 + +`import a.b.c.d` 的语义为: + +1. 如果 `kcl.mod` 文件不存在,将当前目录作为包的根路径,并从当前目前查找 `a/b/c/d` 路径 +2. 如果 `kcl.mod` 文件存在,从 `ROOT_PATH/a/b/c/d` 查找,否则抛出一个导入错误 + +根路径 `ROOT_PATH` 的定义为: + +从当前目录或者父级目录中查找 `kcl.mod` 文件对应的目录。 + +```bash +. +└── root + ├── kcl.mod + ├── model + │ ├── model1.k + | ├── model2.k + │ └── main.k + ├── service + │ └── service1.k + └── mixin + └── mixin1.k +``` + +main.k: + +```python +import service # `root package` and `kcl.mod` are in the same directory +import mixin # `root package` and `kcl.mod` are in the same directory + +myModel = model.CatalogItem {} +``` + +请注意,对于 KCL 入口文件 `main.k`,不能导入所在文件夹,否则会出现递归导入错误: + +```python +import model # Error: recursively loading +``` + +### 动态参数 + +假设某些字段需要像用户输入一样动态传入,我们可以在模块中定义一个动态参数: + +```python +bankCard = option("bankCard") # Get bankCard through the option function. +``` + +我们可以如下使用 module: + +```bash +kcl employee.k -D bankCard=123 +``` + +目前,支持顶级参数的类型有数字、字符串、布尔、列表和字典。 + +```bash +kcl main.k -D list_key='[1,2,3]' -D dict_key='{"key":"value"}' +``` + +请注意,命令行中引号 `"` 等符号需要使用 `\` 进行转义 + +#### Setting 文件形式的参数 + +此外,它还支持输入一个 YAML 文件作为顶级参数。 + +```yaml +kcl_options: + - key: key_number + value: 1 + - key: key_dict + value: + innerDictKey: innerDictValue + - key: key_list + value: + - 1 + - 2 + - 3 + - key: bankCard + value: 123 +``` + +```bash +kcl -Y setting.yaml employee.k +``` + +此外,setting 文件还支持配置命令行编译参数如下: + +```yaml +kcl_cli_configs: + files: + - file1.k + - file2.k + disable_none: true + strict_range_check: true + debug: 1 + verbose: 1 + sort_keys: true + output: ./stdout.golden + overrides: + - app.image=new_image + path_selector: + - config + package_maps: + k8s: /Users/.kcl/kpm/k8s_1.24 +kcl_options: + - key: image + value: docker.io/kcllang/kcl:latest +``` + +KCL CLI -Y 参数还支持多文件配置,并支持编译参数和顶级参数的单独写入与合并。 + +```bash +kcl -Y compile_setting.yaml option_setting.yaml +``` + +- `compile_setting.yaml` + +```yaml +kcl_cli_configs: + files: + - file1.k + - file2.k + disable_none: true + strict_range_check: true + debug: 1 + verbose: 1 + output: ./stdout.golden +``` + +- `option_setting.yaml` + +```yaml +kcl_options: + - key: image + value: docker.io/kcllang/kcl:latest +``` + +我们可以使用以下指令获取每个参数的含义 + +```bash +kcl --help +``` + +#### Option Functions + +我们可以在 KCL 代码中使用 `option` 获取顶级参数。 + +```python +value = option(key="key", type='str', default="default_value", required=True, help="Set key value") +``` + +参数 + +- **key**: 参数的键。 +- **type**: 要转换的参数类型。 +- **default**: 参数默认值。 +- **required**: 当未提供参数和缺省值,且参数的 required 为 True 时报告错误。 +- **help**: 帮助信息。 + +### 多文件编译 + +除了上面的 KCL 单文件执行之外,我们还可以使用以下命令同时编译多个 KCL 入口文件: + +```bash +kcl main_1.k main_2.k ... main_n.k +``` + +main_1.k + +```python +a = 1 +b = 2 +``` + +main_2.k + +```python +c = 3 +d = 4 +``` + +输出结果为: + +```yaml +a: 1 +b: 2 +c: 3 +d: 4 +``` + +利用**多文件编译**,我们可以组合多个 KCL 文件,而无需使用 import 管理文件。 我们来看一个结合**多文件编译**和 **schema 实例**的例子。 + +model.k + +```python +schema Model: + name: str + labels?: {str:} + annotations?: {str:} + replicas: int + +_model1 = Model { + name = "model1" + labels.key1 = "value1" + labels.key2 = "value2" + annotations.key = "value" + replicas = 2 +} + +_model2 = Model { + name = "model2" + replicas = 3 +} +``` + +backend.k + +```python +import manifests + +schema Backend: + apiVersion: str = "v1" + kind: str = "Deployment" + metadata: {str:} + spec: {str:} = { + minReadySeconds = 0 + paused = False + progressDeadlineSeconds = 600 + replicas = 1 + revisionHistoryLimit = 10 + selector = {} + } + +_backends = [Backend { + metadata.name = model.name + metadata.labels = model.labels + metadata.annotations = model.annotations + spec.selector.matchLabels: model.labels + spec.replicas = model.replicas +} for model in Model.instances()] # Schema Model is defined in model.k + +manifests.yaml_stream(_backends) +``` + +命令为: + +```bash +kcl model.k backend.k +``` + +输出为: + +```yaml +apiVersion: v1 +kind: Deployment +metadata: + name: model1 + labels: + key1: value1 + key2: value2 + annotations: + key: value +spec: + minReadySeconds: 0 + paused: false + progressDeadlineSeconds: 600 + replicas: 2 + revisionHistoryLimit: 10 + selector: + matchLabels: + key1: value1 + key2: value2 +--- +apiVersion: v1 +kind: Deployment +metadata: + name: model2 +spec: + minReadySeconds: 0 + paused: false + progressDeadlineSeconds: 600 + replicas: 3 + revisionHistoryLimit: 10 + selector: {} +``` + +### KCL 变量查询 + +我们可以在 KCL CLI 使用 `-S|--path-selector` 参数从 KCL 模型中查询一个或多个值。 + +变量查询形式如下: + +`var.name` + +#### 示例 + +Code structure: + +```bash +. +├── kcl.mod +└── main.k + └── pkg + └── model.k +``` + +pkg/model.k: + +```python +schema Person: + name: str + age: int + +var = Person { + name = "Alice" + age = 18 +} +``` + +main.k + +```python +import pkg + +var = pkg.Person { + name = "Bob" + age = 10 +} +``` + +命令为: + +```bash +kcl main.k -S var +``` + +输出结果为: + +```yaml +var: + name: Bob +--- +var: + name: Alice + age: 18 +``` + +### KCL 变量修改 + +除了变量查询,KCL 还允许我们通过 KCL CLI 的 `-O|--overrides` 参数直接修改配置模型中的值。 + +变量修改参数的使用与变量查询类似,参数包含三部分,如 `pkg`、`identifier`、`attribute` 和 `override_value` . + +```bash +kcl main.k -O override_spec +``` + +- `override_spec`: 表示需要修改的配置模型字段和值的统一表示 + +```bash +override_spec: identifier (("=" | ":" | "+=") value | "-") +``` + +- `identifier`: 表示需要修改配置的标识符,通常为 `a.b.c` 或者 `a["dot.key"].c` 的形式 +- `value`: 表示需要修改配置的值,可以是任意合法的 KCL 表达式,比如数字/字符串字面值,list/dict/schema 表达式等 +- `=`, `-` 和 `+=`: 表示用对应的属性运算符修改 identifier 的值 + - 当 identifier 存在时,修改已有 identifier的值为 value + - 当 identifier 不存在时,添加 identifier属性,并将其值设置为 value +- `-`: 表示删除 identifier属性 + - 当 identifier 存在时,直接进行删除 + - 当 identifier 不存在时,对配置不作任何修改 + +请注意,当 `identifier` 出现多次时,修改/删除全部 `identifier` 的值 + +此外,在 KCL 中还提供了 API 用于变量查询和修改,详见 [API 文档](../xlang-api/go-api.md) + +#### 示例 + +##### 修改示例 + +KCL 代码: + +```python +schema Person: + name: str + age: int + +person = Person { + name = "Alice" + age = 18 +} +``` + +命令为: + +```bash +kcl main.k -O :person.name=Bob -O :person.age=10 +``` + +输出结果为: + +```yaml +person: + name: Bob + age: 10 +``` + +此外,当我们使用 KCL CLI `-d` 参数时,KCL 文件将同时修改为以下内容 + +```bash +kcl main.k -O :person.name=Bob -O :person.age=10 -d +``` + +```python +schema Person: + name: str + age: int + +person = Person { + name = "Bob" + age = 10 +} +``` + +##### 删除示例 + +KCL 代码: + +```python +schema Config: + x?: int = 1 + y?: str = "s" + +config = Config { + x = 2 +} +``` + +命令为: + +```bash +kcl main.k -O config.x- +``` + +输出结果为: + +```yaml +config: + y: s +``` + +### 总结 + +本页总结了 KCL 语言中的常用功能。 KCL 作为一种新的语言,会根据配置场景的需求,逐步增加功能特性。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/_category_.json new file mode 100644 index 000000000..a8f409150 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "类型系统", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/types.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/types.md new file mode 100644 index 000000000..182ffaf2b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/lang/types/types.md @@ -0,0 +1,1401 @@ +# 类型系统 + +本文档描述 KCL 的类型系统,包括: + +- 类型规则 +- 类型检查 +- 类型转换 +- 类型推导 + +## 类型规则 + +### 基础定义 + +#### 断言 + +$S$ 的所有自由变量都定义在 $\Gamma$ 中 + +$$ +\Gamma \vdash S +$$ + +$\Gamma$ 是一个变量的类型声明环境(well-formed environment),如:$x_1:T_1$, ..., $x_n:T_n$ + +$S$ 的断言有三种形式: + +**环境断言** 断言表示 $\Gamma$ 是良构类型 (well-formed type) + +$$ +\Gamma \vdash ◇ +$$ + +**良构类型断言** 在环境 $\Gamma$ 下,$nat$ 是类型表达式 + +$$ +\Gamma \vdash nat +$$ + +**类型判断断言** 在环境 $\Gamma$ 下,$E$ 具有类型 $T$ + +$$ +\Gamma \vdash E: T +$$ + +#### 推理规则 + +表示法 + +$$ +\frac{\Gamma \vdash S_1, ..., \Gamma \vdash S_n}{\Gamma \vdash S} +$$ + +推理规则中的 $u$, $v$, $w$ 用于表示变量,$i$, $j$, $k$ 用于表示整数,$a$, $b$ 用于表示浮点数,$s$ 用于表示字符串,$c$ 代表常量(整数、浮点数、字符串、布尔)的字面值, $f$ 用于表示函数, $T$, $S$, $U$ 用于表示类型。 + +## 环境规则 + +Env ⌀ + +$$ +\frac{}{⌀ \vdash ◇ } +$$ + +## 类型定义 + +Type Bool + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash boolean} +$$ + +Type Int + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash integer} +$$ + +Type Float + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash float} +$$ + +Type String + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash string} +$$ + +Type Literal + +$$ +\frac{ c \in \{boolean, integer, float, string\}}{\Gamma \vdash literalof(c)} +$$ + +Type List + +$$ +\frac{\Gamma \vdash T \ T \neq Void}{\Gamma \vdash listof(T) } +$$ + +Type Dict + +$$ +\frac{\Gamma \vdash T_1 \ \Gamma \vdash T_2\ T_1 \neq Void \ \ T_2 \neq Void}{\Gamma \vdash dictof(T_k=T_1, T_v=T_2)} +$$ + +Type Struct + +$$ +\frac{\Gamma \vdash T_{1} \ ... \ \Gamma \vdash T_{n} \ \ T_i \neq Void \ K_1 \neq K_n}{\Gamma \vdash structof(K_1 : T_{1}, ... , K_n : T_{n})} +$$ + +Type Union + +$$ +\frac{\Gamma \vdash T_1 \ ... \ \Gamma \vdash T_n \ \ T_i \neq Void}{\Gamma \vdash unionof(T_1, ..., T_n)} +$$ + +Type None + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash None} +$$ + +Type Undefined + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash Undefined} +$$ + +Type Void + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash Void} +$$ + +Type Any + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash Any} +$$ + +Type Nothing + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash Nothing} +$$ + +## 类型判断规则 + +### Operand Expr + +Exp Truth + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash true: boolean} +$$ + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash false: boolean} +$$ + +Exp Int + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash int: integer} +$$ + +Exp Flt + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash flt: float} +$$ + +Exp Str + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash str: string} +$$ + +Exp None + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash none: none} +$$ + +Exp Undefined + +$$ +\frac{\Gamma \vdash ◇}{\Gamma \vdash undefined: undefined} +$$ + +Expr ListExp + +$$ +\frac{\Gamma \vdash E_1: T_1 \ E_2: T_2 \ ... \ E_n: T_n}{\Gamma \vdash [E_1, E_2, ..., E_n]: listof \ sup(T_1, T_2, ..., T_n)} +$$ + +Expr ListComp + +$$ +\frac{\Gamma \vdash E_1: T_1 \ \Gamma \vdash v: T \ \Gamma \vdash E_2: listof \ T \ \Gamma \vdash E_3: boolean}{\Gamma \vdash [E_1 \ for \ v \ in \ E_2 \ if \ E_3]: listof(T_1) } +$$ + +Expr DictExp + +$$ +\frac{\Gamma \vdash E_{k1}: T_{k1} \ \Gamma \vdash E_{v1}: T_{v1} \ ... \ \Gamma \vdash E_{kn}: T_{kN} \ \Gamma \vdash E_{vn}: T_{vN}}{\Gamma \vdash \{E_{k1}: E_{v1}, ..., E_{{kn}}: E_{vn}\}: dictof(T_{k}=sup(T_{k1}, T_{k2}, ... T_{kn}), \ T_{v}=sup(T_{v1}, T_{v2}, ..., T_{vn}))} +$$ + +Expr DictComp + +$$ +\frac{\Gamma \vdash E_1: T_{rki} \ \Gamma \vdash E_2: T_{rvi} \ \Gamma \vdash v_1: T_k \ \Gamma \vdash v_2: T_v \ \Gamma \vdash E_3: dictof(T_{k}, \ T_{v}) \ \Gamma \vdash E_4: boolean}{\Gamma \vdash \{E_1:E_2 \ for \ (v_1, v_2) \ in \ E_3 \ if \ E_4\}: dictof(T_{k}=sup(T_{rk1}, T_{rk2}, ..., T_{rkn}), T_{v}=sup(T_{rv1}, T_{rv2}, ..., T_{rvn})) } +$$ + +Expr StructExpr + +$$ +\frac{\Gamma \vdash E_{1}: T_{1} \ ... \ \Gamma \vdash E_{n}: T_{n} \ K_1 \neq K_n}{\Gamma \vdash \{K_{1} = E_{1}, ..., K_{{n}} = E_{n}\}: structof(K_1 : T_{1}, ... , K_n : T_{n})} +$$ + +Literal 类型是基础类型的值类型,Union 类型是类型的组合类型,Void、Any、Nothing 是特殊的类型指代,本身没有直接的值表达式对应关系。 + +### Primary Expr + +Expr Index + +$$ +\frac{\Gamma \vdash E: listof(T) \ \Gamma \vdash Index: integer}{\Gamma \vdash E[Index]: T} +$$ + +Expr Call + +$$ +\frac{\Gamma \vdash E_1: T_1 \rightarrow T_2 \ \Gamma \vdash E_2: T_1}{\Gamma \vdash E_1 \ (E_2): T_2} +$$ + +Expr List Selector + +$$ +\frac{\Gamma \vdash E: listof(T) \ \Gamma \vdash Index: integer}{\Gamma \vdash E.[Index]: T} +$$ + +Expr Dict Selector + +$$ +\frac{\Gamma \vdash E: dictof(T_k = T_1, T_v=T_2) \ \Gamma \vdash S_1: string \ ... \ \Gamma \vdash S_n: string}{\Gamma \vdash E.\{S_1, ..., S_n\}: dictof(T_k = T_1, T_v=T_2)} +$$ + +Expr Struct Selector + +$$ +\frac{\Gamma \vdash E: structof(K_1 : T_{1}, ... , K_n : T_{n}) \ \Gamma \vdash K_i: string}{\Gamma \vdash E.K_i: T_{i}} +$$ + +### Unary Expr + +Expr + + +$$ +\frac{\Gamma \vdash E: T \ \ \ T \in \{integer, float\}}{\Gamma \vdash \ +E: T} +$$ + +Expr - + +$$ +\frac{\Gamma \vdash E: T \ \ \ T \in \{integer, float\}}{\Gamma \vdash \ -E: T} +$$ + +Expr ~ + +$$ +\frac{\Gamma \vdash E: integer}{\Gamma \vdash \ ~E: integer} +$$ + +Expr not + +$$ +\frac{\Gamma \vdash E: boolean}{\Gamma \vdash \ not \ E: boolean} +$$ + +### Binary Expr + +算数运算符 + +Expr op, op $\in$ {-, /, %, \*\*, //} + +$$ +\frac{\Gamma \vdash E_1: T \ \ \ \Gamma \vdash E_2: T \ \ \ T \in \{integer, float\}}{\Gamma \vdash E_1 \ op \ E_2: T} +$$ + +Expr + + +$$ +\frac{\Gamma \vdash E_1: T \ \ \ \Gamma \vdash E_2: T \ \ \ T \in \{integer, float, string, listof(T_1)\}}{\Gamma \vdash E_1 \ + \ E_2: T} +$$ + +Expr \* + +$$ +\frac{\Gamma \vdash E_1: T_1 \ \ \ \Gamma \vdash E_2: T_2 \ \ \ \ (T_1==T_2 \in \{integer, float\}) \ or \ (T_1 == interger \ and \ T_2 \ \in \ \{string, listof(T_3)\}) \ or \ (T_2 == interger \ and \ T_1 \ \in \ \{string, listof(T_3)\})} {\Gamma \vdash E_1 \ * \ E_2: T} +$$ + +示例 + +Expr % + +$$ +\frac{\Gamma \vdash E_1: interger \ \ \ \Gamma \vdash E_2: integer}{\Gamma \vdash E_1 \ \% \ E_2: interger} +$$ + +逻辑运算符 + +Expr op, op $\in$ \{or, and\} + +$$ +\frac{\Gamma \vdash E_1: boolean \ \ \ \Gamma \vdash E_2: boolean}{\Gamma \vdash E_1 \ op \ E_2: boolean} +$$ + +示例 + +Expr and + +$$ +\frac{\Gamma \vdash E_1: boolean \ \ \ \Gamma \vdash E_2: boolean}{\Gamma \vdash E_1 \ and \ E_2: boolean} +$$ + +比较运算符 + +Expr op, op $\in$ \{==, !=, <, >, <=, >=\} + +$$ +\frac{\Gamma \vdash E_1: T \ \ \ \Gamma \vdash E_2: T}{\Gamma \vdash E_1 \ op \ E_2: boolean} +$$ + +示例 + +Expr > + +$$ +\frac{\Gamma \vdash E_1: boolean \ \ \ \Gamma \vdash E_2: boolean}{\Gamma \vdash E_1 \ > \ E_2: boolean} +$$ + +位运算符 + +Expr op, op $\in$ {&, ^, ~, <<, >>} + +$$ +\frac{\Gamma \vdash E_1: integer \ \ \ \Gamma \vdash E_2: integer}{\Gamma \vdash E_1 \ op \ E_2: integer} +$$ + +Expr | + +$$ +\frac{\Gamma \vdash E_1: T \ \ \ \Gamma \vdash E_2: T \ \ \ T \in \{integer, listof(T_1), dictof(T_k, T_v), structof(K_1=T_1, ..., K_n=T_n)\}}{\Gamma \vdash E_1 \ | \ E_2: T} +$$ + +成员运算符 + +Expr op, op $\in$ {in, not in} + +$$ +\frac{\Gamma \vdash E_1: string \ \ \ \Gamma \vdash E_2: T \ \ \ T \in \{dictof, structof\}}{\Gamma \vdash E_1 \ op \ E_2: bool} +$$ + +Expr op, op $\in$ {in, not in} + +$$ +\frac{\Gamma \vdash E_1: T \ \ \ \Gamma \vdash E_2: listof(S), T \sqsubseteq S}{\Gamma \vdash E_1 \ op \ E_2: bool} +$$ + +身份运算符 + +Expr op $\in$ {is, is not} + +$$ +\frac{\Gamma \vdash E_1: T \ \ \ \Gamma \vdash E_2: T}{\Gamma \vdash E_1 \ op \ E_2: bool} +$$ + +### IF Expr + +Expr If + +$$ +\frac{\Gamma \vdash E_1: boolean \ \ \ \Gamma \vdash E_2: T \ \ \ \Gamma \vdash E_3: T}{\Gamma \vdash if \ E_1 \ then \ E_2 \ else \ E_3: T} +$$ + +### Stmt + +Stmt If + +$$ +\frac{\Gamma \vdash E_1: boolean \ \ \ \Gamma \vdash S_1: Void \ \ \ \Gamma \vdash S_2: Void}{\Gamma \vdash if \ E_1 \ then \ S_1 \ else \ S_2: Void} +$$ + +Stmt Assign + +$$ +\frac{\Gamma \vdash id: T_0 \ \ \ \Gamma \vdash T_1 \ \ \ \Gamma \vdash E: T_2}{\Gamma \vdash id: T_1 \ = \ E : Void} +$$ + +Type Alias + +$$ +\frac{\Gamma \vdash id: T_0 \ \ \ \Gamma \vdash T_1}{\Gamma \vdash type \ id \ = \ T_1 : Void} +$$ + +## Union + +### Union 规则 + +List Union + +$$ +\frac{\Gamma \vdash \ listof(T) \ \ \ \Gamma \vdash \ listof(S)}{\Gamma \vdash \ listof(unionof(T, S))} +$$ + +Dict Union + +$$ +\frac{\Gamma \vdash \ dictof(T_1, T_2) \ \ \ \Gamma \vdash \ dictof(S_1, S_2)}{\Gamma \vdash \ dictof(unionof(T_1, S_1), unionof(T_2, S_2))} +$$ + +Struct Union + +给定两个结构体 $structof(K_{1}: T_{1}, ..., K_{n}: T_{n}),structof(H_{1}: S_{1}, ..., H_{m}: S_{n})$ + +定义他们的 union 类型: + +$$ +structof(J_{1}: U_{1}, ..., J_{p}: U_{n}) = structof(K_{1}: T_{1}, ..., K_{n}: T_{n}) \bigcup structof(H_{1}: S_{1}, ..., H_{m}: S_{n}) +$$ + +例如: + +$$ +structof() \ \bigcup \ structof(H_{1}: T_{1}, ..., H_{m}: T_{n}) = structof(H_{1}: T_{1}, ..., H_{m}: T_{n}) +$$ + +$$ +structof(K_{1}: T_{1}, ..., K_{n}: T_{n}) \ \bigcup \ structof(H_{1}: S_{1}, ..., H_{m}: S_{n}) = structof(K_1: T_1) :: (structof(K_{2}: T_{2}, ..., K_{n}: T_{n}) \ \bigcup \ structof(H_{1}: S_{1}, ..., H_{m}: S_{n})) +$$ + +其中把 "::" 表示把一个对偶加入到一个结构的操作,定义如下: + +$$ +structof(K_{1}: T_{1}) :: structof() = structof(K_{1}: T_{1}) +$$ + +$$ +structof(K_{1}: T_{1}) :: structof(K_{1}: T_{1}', ..., K_n: T_{n}) = structof(K_{1}: union\_op(T_{1}, T_{1}'), ..., K_{n}: T_{n}) +$$ + +$$ +structof(K_{1}: T_{1}) :: structof(K_{2}: T_{2}, ..., K_n: T_{n}) = structof(K_{2}: T_2) :: structof(K_{1}: T_1) :: structof(K_{3}: T_3, ..., K_{n}: T_{n}) +$$ + +基于此,两个 Struct 的 union 定义为: + +$$ +\frac{\Gamma \vdash structof(K_{1}: T_{1}, ..., K_{n}: T_{n}) \ \Gamma \vdash structof(H_{1}: S_{1}, ..., H_{m}: S_{n}) \ structof(J_{1}: U_{1}, ..., J_{p}: U_{n}) = structof(K_{1}: T_{1}, ..., K_{n}: T_{n}) \bigcup structof(H_{1}: S_{1}, ..., H_{m}: S_{n})}{\Gamma \vdash structof(J_{1}: U_{1}, ..., J_{p}: U_{n}))} +$$ + +其中 $union\_op(T_1, T_2)$ 表示对相同 $K_i$ 的不同类型的判断操作: + +- 当 $T_1$ 与 $T_2$ 有偏序关系时, 如果 $T_1 \sqsubseteq T_2$ 时,返回 $T_2$,否则返回 $T_1$,即取最小上界 +- 当 $T_1$ 与 $T_2$ 不存在偏序关系时,有三种可选的处理逻辑: + - 结构体 union 失败,返回 type_error + - 返回后者的类型,此处为 $T_2$ + - 返回类型 $unionof(T_1, T_2)$ + +此处需要根据实际需求选择适当的处理方式。 + +结构体继承可以看做一种特殊的 union,整体逻辑与 union 相似,但在 $union\_op(T_1, T_2)$ 中对相同 $K_i$ 的不同类型的判断操作如下: + +- 当 $T_1$ 与 $T_2$ 有偏序关系且 $T_1 \sqsubseteq T_2$ 时,返回 $T_1$,即仅当 $T_1$ 是 $T_2$ 的下界时以下界 $T_1$ 为准 +- 否则返回 type_error + +通过这样的继承设计可以实现分层的、自下而上逐层收缩的类型定义。 + +## Operation + +KCL 支持对结构体属性进行如 `p op E` 形式的操作。 即对给定结构体 $A: structof(K_{1}: T_{1}, ..., K_{n}: T_{n})$, 对结构体中的路径 `p` 以 `E` 的值进行指定的操作(如 union,assign,insert 等)。 + +定义如下更新操作: + +$$ +\frac{{\Gamma\vdash A: structof(K_{1}: T_{1}, ..., K_{n}: T_{n})}  {\Gamma\vdash p \in (K_{1}, ..., K_{n})} \ {\Gamma\vdash e:T}   k \neq k_1, ..., k \neq k_n} +{ A \{p \ op \ e\}:\{K_1:T_1, ..., K_n:T_n\}∪\{p:T\}} +$$ + +即对路径 $p$ 进行操作本质上是对两个结构体的一种 union,对同名属性类型 union 时的规则根据情况而定。例如路径 $p$ 是一个可用作字段名的标识符 $p=k_1$,并且结构体 A 中字段名也是 $k_1$,它的类型为 $T_1$,并且表达式 $e$ 的类型也为 $T_1$ ,那么 + +$$ +\frac{{\Gamma\vdash A: structof(K_{1}: T_{1}, ..., K_{n}: T_{n})}  {\Gamma\vdash p = K_{1}} \ {\Gamma\vdash e:T_1}   k \neq k_1, ..., k \neq k_n} +{ A \{p \ op \ e\}:\{K_1:T_1, ..., K_n:T_n\}} +$$ + +注意: + +- 此处表达式 $e$ 的类型 $T_1$ 同原先同名属性 $K_1$ 的具有相同的类型。可根据实际情况需要适当放松,如 $e$ 的类型 $\sqsubseteq T_1$ 即可。 +- 对于多层结构体嵌套的操作,递归的使用以上规则即可。 + +## 类型偏序 + +### 基础类型 + +$$ +Type \ T \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ T +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Bool \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Int \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Float \sqsubseteq Type \ Any +$$ + +$$ +Type \ Int \sqsubseteq Type \ Float +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ String \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Literal \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ List \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Dict \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Struct \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ None \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Void \sqsubseteq Type \ Any +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Any +$$ + +### 字面值类型 + +$$ +Type \ Literal(Bool) \sqsubseteq Type \ Bool +$$ + +$$ +Type \ Literal(Int) \sqsubseteq Type \ Int +$$ + +$$ +Type \ Literal(Float) \sqsubseteq Type \ Float +$$ + +$$ +Type \ Literal(String) \sqsubseteq Type \ String +$$ + +### 联合类型 + +$$ +Type \ X \sqsubseteq Type \ Union(X, Y) +$$ + +### 自反 + +$$ +Type \ X \sqsubseteq Type \ X +$$ + +示例 + +$$ +Type \ Bool \sqsubseteq Type \ Bool +$$ + +$$ +Type \ Int \sqsubseteq Type \ Int +$$ + +$$ +Type \ Float \sqsubseteq Type \ Float +$$ + +$$ +Type \ String \sqsubseteq Type \ String +$$ + +$$ +Type \ List \sqsubseteq Type \ List +$$ + +$$ +Type \ Dict \sqsubseteq Type \ Dict +$$ + +$$ +Type \ Struct \sqsubseteq Type \ Struct +$$ + +$$ +Type \ Nothing \sqsubseteq Type \ Nothing +$$ + +$$ +Type \ Any \sqsubseteq Type \ Any +$$ + +$$ +Type \ Union(Type Int, Type Bool) \sqsubseteq Type \ Union(Type Int, Type Bool) +$$ + +### 传递 + +$$ +Type \ X \sqsubseteq Type \ Z \ if \ Type \ X \sqsubseteq Type \ Y \ and \ Type \ Y \sqsubseteq \ Type \ Z +$$ + +### 包含 + +$$ +Type \ List(T_1) \sqsubseteq Type \ List(T_2) \ if \ T_1 \sqsubseteq T_2 +$$ + +$$ +Type \ Dict(T_{k1}, T_{v1}) \sqsubseteq Type \ Dict(T_{k2}, T_{v2}) \ if \ T_{k1} \sqsubseteq T_{k2} \ and \ T_{v1} \sqsubseteq T_{v1} +$$ + +$$ +Type \ Structure(K_1: T_{a1}, K_2: T_{a2}, ..., K_n: T_{an}) \sqsubseteq Type \ Structure(K_1: T_{b1}, K_2: T_{b2}, ..., K_n: T_{bn}) \ if \ T_{a1} \sqsubseteq T_{b1} \ and \ T_{a2} \sqsubseteq T_{b2} \ and \ ... \ and \ T_{an} \sqsubseteq T_{bn} +$$ + +### 继承 + +$$ +Type \ Struct \ A \sqsubseteq Type \ Struct \ B \ if \ A \ inherits \ B +$$ + +### None + +$$ +Type \ None \sqsubseteq Type \ X, X \notin \{Type \ Nothing, \ Type \ Void\} +$$ + +### Undefined + +$$ +Type \ Undefined \sqsubseteq Type \ X, X \notin \{Type \ Nothing, \ Type \ Void\} +$$ + +## 相等性 + +交换律 + +$$ +Type \ Union(X, Y) == Type \ Union(Y, X) +$$ + +示例 + +$$ +Type \ Union(Int, Bool) == Type \ Union(Bool, Int) +$$ + +结合律 + +$$ +Type \ Union(Union(X, Y), Z) == Type \ Union(X, Union(Y, Z)) +$$ + +示例 + +$$ +Type \ Union(Union(Int, String), Bool) == Type \ Union(Int, Union(String, Bool)) +$$ + +幂等性 + +$$ +Type \ Union(X, X) == Type \ X +$$ + +示例 + +$$ +Type \ Union(Int, Int) == Type \ Int +$$ + +偏序推导 + +$$ +Type \ Union(X, Y) == Type \ Y \ if \ X \sqsubseteq Y +$$ + +示例 + +假设 Struct A 继承 Struct B + +$$ +Type \ Union(A, B) == Type \ B +$$ + +幂等性是偏序自反的一个特例 + +### List + +$$ +Type \ List(X) == Type \ List(Y) \ if \ X == Y +$$ + +### Dict + +$$ +Type \ Dict(T_k, T_v) == Type \ Dict(S_k, S_v) \ if \ T_k == S_k \ and \ T_v == S_v +$$ + +### Struct + +$$ +Type \ Struct(K_1: T_{1}, K_2: T_{2}, ..., K_n: T_{n}) == Type \ Struct(K_1: S_{1}, K_2: S_{2}, ..., K_n: S_{n}) \ if \ T_{1} == S_{1} \ and \ ... \ and \ T_{n} == S_{n} +$$ + +### 偏序检查 + +$$ +Type \ X == Type \ Y \ if \ Type \ X \sqsubseteq Type \ Y \ and \ Type \ Y \sqsubseteq \ Type \ X +$$ + +## 基础方法 + +- sup(t1: T, t2: T) -> T: 根据类型偏序计算两类型 t1, t2 的最小上界。需要动态创建 union type。 +- typeEqual(t1: T, t2: T) -> bool: 比较两类型 t1, t2 是否相等。 +- typeToString(t: T) -> string: 自顶向下递归解析并转化类型成对应的字符串类型。 + +### Sup Function + +- 暂不考虑类型参数,条件类型等特性 +- 使用一个有序集合存储 UnionType 的所有类型 +- 使用一个全局的 Map 根据 UnionType 的名称存储产生的所有 UnionType +- 根据偏序关系计算类型之间的包含关系 + +```go +// The Sup function returns the minimum supremum of all types in an array of types +func Sup(types: T[]) -> T { + typeOf(types, removeSubTypes=true) +} + +// Build a sup type from types [T1, T2, ... , Tn] +func typeOf(types: T[], removeSubTypes: bool = false) -> T { + assert isNotNullOrEmpty(types) + // 1. Initialize an ordered set to store the type array + typeSet: Set[T] = {} + // 2. Add the type array to the ordered set for sorting by the type id and de-duplication + addTypesToTypeSet(typeSet, types) + // 3. Remove sub types according to partial order relation rules e.g. sub schema types + if removeSubTypes { + removeSubTypes(typeSet) + } + if len(typeSet) == 1 { + // If the typeSet has only one type, return it + return typeSet[0] + } + // 4. Get or set the union type from the global union type map + id := getIdentifierFromTypeSet(typeSet) + unionType := globalUnionTypeMap.get(id) + if !unionType { + unionType = createUnionType(typeSet) // Build a new union type + globalUnionTypeMap.set(id, unionType) + } + return unionType +} + +// Add many types into the type set +func addTypesToTypeSet(typeSet: Set[T], types: T[]) -> void { + for type in types { + addTypeToTypeSet(typeSet, type) + } +} + +// Add one type into the type set +func addTypeToTypeSet(typeSet: Set[T], type: T) -> void { + if isUnion(type) { + return addTypesToTypeSet(typeSet, toUnionOf(type).types) + } + // Ignore the void type check + if !isVoid(type) { + // De-duplication according to the type of id + typeSet.add(type) + } +} + +func removeSubTypes(types: Set[T]) -> void { + for source in types { + for target in types { + if !typeEqual(source, target) { + // If the two types have an inheritance relationship, the base class is retained, or if the two types have a partial order relationship according to the relation table. + if (isPartialOrderRelatedTo(source, target)) { + types.remove(source) + } + } + } + } +} + +// isPartialOrderRelatedTo function Determine whether two types have a partial order relationship `source \sqsubseteq target` +// according to the partial order relationship table and rules +func isPartialOrderRelatedTo(source: T, target: T) -> bool { + assert isNotNullOrEmpty(source) + assert isNotNullOrEmpty(target) + if isNoneOrUndefined(source) and !isNothing(target) and !isVoid(target) { + return true + } + if isAny(target) { + return true + } + if typeEqual(source, target) { + return true + } + if isUnion(target) and source in target.types { + return true + } + // Literal Type + if (isStringLiteral(source) and isString(target)) or \ + (isBooleanLiteral(source) and isBool(target)) or \ + (isIntLiteral(source) and isInt(target)) or \ + (isFloatLiteral(source) and isFloat(target)) { + return true + } + if isInt(source) and isFloat(target) { + return true + } + if isList(source) and isList(target) { + return isPartialOrderRelatedTo(toListOf(source).eleType, toListOf(target).eleType + } + if isDict(source) and isDict(target) { + return isPartialOrderRelatedTo(toDictOf(source).keyType, toDictOf(target).keyType) and isPartialOrderRelatedTo(toDictOf(source).valueType, toDictOf(target).valueType) + } + if isStruct(source) and isStruct(target) { + if isTypeDerivedFrom(source, target) { + return true + } + // Empty Object + if len(target.keys) == 0 { + return true + } + if any([key Not in source.keys for key in target.keys]) { + return false + } + for key, sourceType in (source.keys, source.types) { + targetType = getKeyType(target, key) ? getKeyType(target, key) : anyTypeOf() + if !isPartialOrderRelatedTo(sourceType, targetType) { + return false + } + } + return true + } + return false +} +``` + +## 类型检查 + +### 类型检查器 + +类型检查器通过语法制导翻译的方式,自顶向下遍历语法树,并根据上下文有关的**定型规则**来判定程序构造是否为良类型程序。 + +类型检查器依赖类型规则,类型环境 $\Gamma$ 的信息记入符号表。对类型表达式采用抽象语法,如 listof(T)。类型检查失败时产生 type_error,并根据语法上下文产生错误信息。 + +### 基础方法 + +1. isUpperBound(t1, t2): supUnify(t1, t2) == t2 +2. supUnify(t1, t2): + +- 对于基础类型,根据偏序关系计算 sup(t1, t2) +- 对于 list、 dict、 Struct, 递归地对其中元素的类型进行 supUnify +- 不存在偏序关系时,返回 Nothing + +### 检查逻辑 + +#### Operand Expr + +$D \to id: T$ + +``` +env.addtype(id.entry, T.type) +``` + +$T \to boolean$ + +``` +T.type = boolean +``` + +$T \to integer$ + +``` +T.type = integer +``` + +$T \to float$ + +``` +T.type = float +``` + +$T \to string$ + +``` +T.type = string +``` + +$T \to c, \ c \in \{boolean, integer, float, string\}$ + +``` +T.type = literalof(c) +``` + +$T \to None$ + +``` +T.type = None +``` + +$T \to Undefined$ + +``` +T.type = Undefined +``` + +$T \to \ [T_1]$ + +``` +T.type = listof (T1.type) +``` + +$T \to { \{T_1: T_2\} }$ + +``` +T.type = dictof (T1.type: T2.type) +``` + +$T \to { \{N_1: T_1, N2: T_2, ..., N_n: T_n\} }$ + +``` +T.type = structof (N1: T1.type, N2: T2.type, ..., Nn: Tn.type) +``` + +$E \to id$ + +``` +E.type = env.lookup(id.entry) +``` + +$E \to [E_1, E_2, ..., E_n]$ + +``` +func listExpr(E) { + supe = sup([e.type for e in E]]) + E.type = listof(type) +} +``` + +$E \to [E_1 \ for \ E_2 \ in \ E_3 \ if \ E_4]$ + +``` +func listComp(E) { + if !typeEqual(E4.type, boolean) { + raise type_error + } + if !isUpperBound(listof(Any), E3.type) { + raise type_error(E) + } + if !isUpperBound(E3.type, E2.type) { + raise type_error(E) + } + E.type = listof(E1.type) +} +``` + +$E \to \{E_{k1}: E_{v1}, ..., E_{kn}: E_{vn}\}$ + +``` +func dictExpr(E) { + supk := sup([e.type for e in E.keys()]]) + supv := sup([e.type for e in E.values()]]) + E.type = dictof(supk, supv) +} +``` + +$E \to \{E_1:E_2 \ for \ (E_3, E_4) \ in \ E_5 \ if \ E_6\}$ + +``` +func dictComp(E) { + if !typeEqual(E6.type, boolean) { + raise type_error(E) + } + if !isUpperBound(dictof(Any, Any), E5.type) { + raise type_error(E) + } + if !isUpperBound(E5.type, dictof(E3.type, E4.type)) { + raise type_error(E) + } + E.type = dictof(E1.type, E2.type) +} +``` + +$E \to \{E_{k1}: E_{v1}, ..., E_{kn}: E_{vn}\}$ + +``` +func dictExpr(E) { + supk := sup(Ek1, ..., Ekn) + supv = sup(Ev1, ..., Evn) + E.type = dictof(supk, supv) +} +``` + +$E \to \{N_{1} = E_{1}, ..., N_{{n}} = E_{n}\}$ + +``` +func structExpr(E) { + Struct = structof() + for n, e in E { + Struct.add(n, e.type) + } + E.type = Struct +} +``` + +#### Primary Expr + +$E \to E_1[E_2]$ + +``` +func sliceSuffix(E) { + if !isUpperBound(listof(Any), E.E1.type) { + raise type_error(E) + } + if typeEqual(E.E2.type, integer) { + raise type_error(E) + } + E.type = E.E1.type.eleType +} +``` + +$E \to E_1(E_2)$ + +``` +func callSuffix(E) { + if !typeEqual(E.E1.type, func) { + raise type_error(E) + } + if !isUpperBound(listof(E.E1.arguType), E.E2.type) { + raise type_error(E) + } + E.type = E.E1.returnType +} +``` + +#### Unary Expr + +根据每条双目运算符的推理规则推导,以 '+' 为例 + +$E \to + E_1$ + +``` +func Plus(E) { + if !typeEqual(E.E1.type, [integer, float]) { + raise type_error(E) + } + E.type = E.E1.type +} +``` + +#### Binary Expr + +根据每条双目运算符的推理规则推导,以 '%' 为例 + +$E \to E_1 \ % \ E_2$ + +``` +func Mod(E) { + if !(typeEqual(E.E1.type, [integer, float]) && typeEqual(E.E2.type, [integer, float])) { + raise type_error(E) + } + E.type = E.E1.type +} +``` + +#### IF Binary Expr + +$E \to if E_1 \ then \ E_2 else \ E_3$ + +``` +func ifExpr(E) { + if !typeEqual(E.type, boolean) { + raise type_error(E) + } + if !typeEqual(E_2.type, E_3.type) { + raise type_error(E) + } + E.type = E_2.type +} +``` + +#### Stmt + +$S \to if \ E \ then \ S_1 \ else \ S_2$ + +``` +func ifStmt(S) { + if !typeEqual(S.E.type, boolean) { + raise type_error(E) + } + if !typeEqual(S.S1.type, S.S2.type) { + raise type_error(E) + } + S.type = S.S1.type +} +``` + +$S \to id: T = E$ + +$S \to id = T E$ + +``` +func assignStmt(S) { + tpe := env.lookup(id.entry) + if tpe != nil && tpe != S.T { + raise type_error(E) + } + if isUpperBound(tpe, E.type) { + raise type_error(E) + } + env.addtype(id.entry, T.type) +} +``` + +## 类型转换 + +### 基础定义 + +通过语法制导翻译的方式,根据运算符特征,对参与运算的值类型进行自动类型转换 + +### 转换规则 + +$E \to E_1 \ op \ E_2, , op \in \{+, -, *, /, \%, **, //\}$ + +``` +func binOp(E) { + if E.E1.type == integer and E.E2.type == integer { + E.type = integer + } else if E.E1.type == integer and E.E2.type == float { + E.type = float + } else if E.E1.type == float and E.E2.type == integer { + E.type = float + } else if E.E1.type == float and E.E2.type == float { + E.type = float + } +} +``` + +## 类型推导 + +### 基础定义 + +- 在类型信息不完全的情况下类型规则推导、重建类型 +- 自底向上推导并重建数程序中的数据结构类型,如基础类型,list, dict, Struct + +### 基础方法 + +1. typeOf(expr, subst): 输入为表达式和代换规则集合,返回 expr 的类型和新的代换规则集合 +2. unifier(t1, t2, subst, expr) 用 t1=t2 尝试代换,如果代换成功(未出现且无冲突),则将 t1=t2 加入 subst 并返回 subst。否则报错已出现或有冲突。 + +### 推导逻辑 + +$E \to id = E_1$ + +``` +func assignExpr(E, subst) { + return unifier(E.id.type, E.E_1.type, subst, E) +} +``` + +$unifier(t1, t2, subst, expr) \rightarrow subst$ + +``` +func unifier(t1, t2, subst, expr) { + t1 = applySubstToTypeEquation(t1, subst) + t2 = applySubstToTypeEquation(t2, subst) + + if t1 == t2 { + return subst + } + + if isTypeVar(t1) { + if isNoOccur(t1, t2) { + addTypeEquationToSubst(subst, t1, t2) + return subst + } else { + raise occurrence_violation_error(t1, t2, expr) + } + } + + if isTypeVar(t2) { + if isNoOccur(t2, t1) { + addTypeEquationToSubst(subst, t2, t1) + return subst + } else { + raise occurrence_violation_error(t2, t1, expr) + } + } + + if isList(t1) and isList(t2) { + return unifier(toListOf(t1).eleType, toListOf(t2).eleType, subst, expr) + } + if isDict(t1) and isDict(t2) { + dict1of := toDictOf(t1) + dict2of := toDictOf(t2) + subst = unifier(dict1of.keyType, dict2of.keyType, subst, expr) + subst = unifier(dict1of.valueType, dict2of.valueType, subst, expr) + return subst + } + if isStruct(t1) and isStruct(t2) { + Struct1of := tostructof(t1) + Struct2of := tostructof(t2) + for key, _ in Struct1of { + subst = unifier(t1[key].type, t2[key].type, subst, expr) + } + return subst + } + + raise unification_error(t1, t2, expr) +} + +func applySubstToTypeEquation(t, subst) { + // walks through the type t, replacing each type variable by its binding in the substitution +σ. If a variable is Not bound in the substitution, then it is left unchanged. + if isBasicType(t) { + return t + } + if isList(t) { + return listOf(applySubstToTypeEquation(toListOf(t).eleType, subst)) + } + if isDict(t) { + dictof := toDictOf(t) + kT := applySubstToTypeEquation(dictof.keyType, subst) + vT := applySubstToTypeEquation(dictof.valueType, subst) + return dictOf(kT, vT) + } + if isStruct(t) { + structof := tostructof(t) + s := structof() + for key, type in Struct1of { + kT := applySubstToTypeEquation(type, subst) + s.add(key, kT) + } + return s + } + if hasTypeVar(t) { + for tvar in t.vars { + if tvar in subst { + *tvar = subst[tvar] + } + } + } + return t +} + +func addTypeEquationToSubst(subst, tvar, t) { + // takes the substitution σ and adds the equation tv = t to it + for _, t in subst { + for tvar in t.vars { + tmp := applyOneSubst(tsvar, tvar, t) + *tvar = tmp + } + } + subst.add(tvar, t) +} + +func applyOneSubst(t0, tvar, t1) { + // substituting t1 for every occurrence of tv in t0. + if isBasicType(t0) { + return t0 + } + if isList(t0) { + return listOf(applyOneSubst(toListOf(t).eleType, tvar, t1)) + } + if isDict(t0) { + dictof := toDictOf(t) + kT := applyOneSubst(dictof.keyType, tvar, t1) + vT := applyOneSubst(dictof.valueType, tvar, t1) + return dictOf(kT, vT) + } + if isStruct(t0) { + structof := tostructof(t) + s := structof() + for key, type in Struct1of { + kT := applyOneSubst(type, tvar, t1) + s.add(key, kT) + } + return s + } + if t0 == tvar { + return t1 + } + return t0 +} + +func isNoOccur(tvar, t) { + // No variable bound in the substitution occurs in any of the right-hand sides of the substitution. + if isBasicType(t) { + return true + } + if isList(t) { + return isNoOccur(tvar, toListOf(t).eleType) + } + if isDict(t) { + dictof := toDictOf(t) + return isNoOccur(tvar, dictof.keyType) and isNoOccur(tvar, dictof.valueType) + } + if isStruct(t) { + structof := tostructof(t) + noOccur := true + for _, type in structof { + noOccur = noOccur and isNoOccur(tvar, type) + } + return noOccur + } + return tvar != t +} +``` + +### 示例 + +#### 正常推导 + +``` +T : { + a = 1 + b = "2" + c = a * 2 + d = { + d0 = [a, c] + } +} + +x: T = { + a = 10 +} +``` + +#### Occurrence Violation Error + +``` +T = { + a = a +} +``` + +#### Type Unification Error + +``` +T : { + a = 1 +} + +T : { + a = "1" +} +``` + +## Reference + +- [https://en.wikipedia.org/wiki/Type_system](https://en.wikipedia.org/wiki/Type_system) +- Pierce, Benjamin C. (2002). Types and Programming Languages. MIT Press. +- [https://www.cs.cornell.edu/courses/cs4110/2010fa/](https://www.cs.cornell.edu/courses/cs4110/2010fa/) +- [https://www.typescriptlang.org/docs/handbook/basic-types.html](https://www.typescriptlang.org/docs/handbook/basic-types.html) +- [https://www.typescriptlang.org/docs/handbook/advanced-types.html](https://www.typescriptlang.org/docs/handbook/advanced-types.html) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/_category_.json new file mode 100644 index 000000000..53e27fd40 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "模块系统", + "position": 2 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/base64.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/base64.md new file mode 100644 index 000000000..71d70481a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/base64.md @@ -0,0 +1,31 @@ +--- +title: "base64" +linkTitle: "base64" +type: "docs" +description: base64 编码解码 +weight: 100 +--- + +## encode + +`encode(value: str, encoding: str = "utf-8") -> str` + +使用注册的编码器对字符串 `value` 进行编码。 + +```python +import base64 + +abcd_base64 = base64.encode("abcd") +``` + +## decode + +`decode(value: str) -> str` + +使用注册的编码器对字符串 `value` 进行解码,解码的结果是一个 utf8 字符串 + +```python +import base64 + +decode = base64.decode("MC4zLjA=") +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/builtin.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/builtin.md new file mode 100644 index 000000000..46d2f18b3 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/builtin.md @@ -0,0 +1,415 @@ +--- +title: "builtin" +sidebar_position: 1 +--- + +KCL 提供了一个内置系统模块的列表,这些模块是自动加载的,无需提供任何模块名称即可直接使用。例如,`print` 就是一个广泛使用的内置模块提供的函数。 + +## 类型转换函数 + +KCL的 `bool`、`int`、`float`、`str`、`list`、`dict`等类型有内置同名的转换函数。其中 `int` 不仅仅可以用于截断浮点数,也可以用来将字符串转化为整数(解析时为10进制,也可以制定其他值)。 + +下面是类型相关函数常见的用法: + +```py +b1 = bool(1) # true +b2 = bool(1.5) # true +b3 = bool("true") # true +b4 = bool("") # false +b5 = bool([]) # false +b6 = bool({}) # false + +i1 = int("11") # 11 +i2 = int("11", base=8) # 9 +i3 = int("11", base=2) # 3 + +f1 = float(1) # 1.0 +f2 = float("1.5") # 1.5 + +s1 = str(1) # 1 + +l1 = list([1, 2, 3]) +``` + +## String 类型成员函数 + +参考 [String 文档](/docs/reference/lang/spec/datatypes) + +## print + +`print(*args:any, end:str='\n')` + +内置的打印函数,提供不同类型的可变参数打印,默认在结尾添加一个换行符号。以下上常见的用法: + +```python +print("hello KCL") +print() +print(None, end=':') +print(None) +print(True) +print(False) +print(123) +print(123.0) +print('abc ${123}') +print("abc ${456}") +print([1,'a', True]) +print(1,'a', True) +print({}) +print({a: 123}) +``` + +输出格式如下: + +```shell +hello KCL + +None:None +True +False +123 +123.0 +abc 123 +abc 456 +[1, 'a', True] +1 a True +{} +{'a': 123} +``` + +如果不希望在默认换行时,可以通过 `end=''` 命名参数重新指定结尾的字符串。 + +## multiplyof + +`multiplyof(a:int, b:int) -> bool` + +判断整数 `a` 是否为 `b` 的整数倍,返回布尔值: + +```python +print(multiplyof(2, 1)) # True +print(multiplyof(1, 2)) # False +print(multiplyof(0, 1)) # True +print(multiplyof(0, 2)) # True +print(multiplyof(1, 0)) # Error +``` + +`0` 是任何数的倍数。但是 `b` 不能为 `0`,否则将抛出异常。 + +## isunique + +`isunique(list: [any]) -> bool` + +判断数组中是否存在重复的元素,返回布尔值: + +```python +print(isunique([])) # True +print(isunique([1])) # True +print(isunique([1, 2])) # True + +print(isunique([1, 1])) # False +print(isunique([1, 1.0])) # False +print(isunique([1.1, 1.1])) # False + +print(isunique(['abc', "abc"])) # False +print(isunique(['abc', "a${'bc'}"])) # False +``` + +## isnullish + +如果输入值是 `None` 或 `Undefined`,则返回 `True`;否则返回 `False`。 + +```python +isnullish(None) # True +isnullish(Undefined) # True +isnullish(0) # False +isnullish([]) # False +isnullish({}) # False +isnullish([None]) # False +isnullish([Undefined]) # False +``` + +需要注意的是整数和浮点数会忽略类型差异,根据值是否相等判断。 + +## len + +`len(x: str | [any] | {:}) -> int` + +返回字符串、列表和数组的长度: + +```python +print(len([])) # 0 +print(len({})) # 0 + +print(len([1])) # 1 +print(len({abc:123})) # 1 + +print("abc") # 3 +``` + +注:不支持对 `schema` 对象计算长度。 + +## abs + +`abs(x: number) -> number` + +计算 `x` 的绝对值。 + +## all_true + +`all_true(x:str|[]|{:}) -> bool` + +判断列表或字典类全部元素为真,用法如下: + +```python +print(all_true([])) # True +print(all_true({})) # True + +print(all_true([True])) # True +print(all_true([1])) # True + +print(all_true([True, False])) # False +print(all_true([True, None])) # False +``` + +当列表为空时返回真。 + + + +## any_true + +`any_true(x:str|[]|{:}) -> bool` + +判断可迭代对象中至少有一个元素为真,用法如下: + +```python +print(any_true([])) # False +print(any_true([1])) # True +``` + +## bin + +`bin(x:number) -> str` + +返回整数的二进制表示的字符串,用法如下: + +```python +print(bin(8)) # 0b1000 +``` + +## hex + +`hex(number)` + +返回整数的十六进制表示的字符串,用法如下: + +```python +print(hex(18)) # 0x12 +``` + +## oct + +`oct(number)` + +返回整数的八进制表示的字符串,用法如下: + +```python +print(oct(10)) # 0o12 +``` + +## option + +`option(key:str, type:str='', required=False, default=None, help="") -> any` + +获取命令行参数输入的值。 + +## ord + +`ord(c) -> int` + +获取字符的 Unicode 码点值,用法如下: + +```python +print(ord('A')) # 65 +print(ord('B')) # 66 +print(ord('C')) # 67 +``` + +## sorted + +`sorted(x: []) -> []` + +返回排序后的列表,用法如下: + +```python +_a = [] +_b = [2, 1] + +_c = sorted(_a) +_d = sorted(_b) + +print(_a) # [] +print(_b) # [2, 1] +print(_c) # [] +print(_d) # [1, 2] +``` + +## range + +`range(start:int, end:int, step=1) -> [int]` + +产生迭代列表,用法如下: + +```python +print(range(1,5)) # [1, 2, 3, 4] +print(range(1,5, 2)) # [1, 3] +print(range(5, 1, -1)) # [5, 4, 3, 2] +``` + +## min + +`min(x:[number]) -> number` + +返回列表中最小的元素,用法如下: + +```python +print(min([1,2])) # 1 +print(min([2,1])) # 1 +``` + + + +## max + +`max(x:[number]) -> number` + +返回列表中最大的元素,用法如下: + +```python +print(max([1,2])) # 2 +print(max([2,1])) # 2 +``` + +## sum + +`sum(x:[number], init_value=0) -> number` + +返回列表中全部元素的和,用法如下: + +``` +print(sum([1,2])) # 3 +print(sum([2,1], 1000)) # 1003 +``` + +## pow + +`pow(x: number, y: number, z: number = None) -> number` + +计算 `x**y`,如果 `z` 非空则计算 `(x**y)%z`,支持整数和浮点数。 + +下面的常见的用法: + +```python +print(pow(2,3)) # 8 +print(pow(2, 3, 5)) # 8%5 == 3 + +print(pow(2, 0.5)) # 1.414 +``` + +## round + +`round(number: int|float, ndigits:int|None) -> float | int` + +返回 `number` 的四舍五入近似值。如果 `ndigits` 非 `None` 则返回浮点数并保留指定位数的小数(不能为负数),否则返回整数结构。 + +下面是常用的用法: + +```python +print(round(1)) # 1 +print(round(1.4)) # 1 +print(round(1.5)) # 2 + +print(round(1.5555, 1)) # 1.6 +print(round(1.5555, 2)) # 1.56 + +print(round(1.5555)) # 2 +print(round(1.5555, 0)) # 2.0 +``` + +需要注意的是,`ndigits` 为 `None` 和 `0` 的区别是前缀返回 `int` 类型、后者返回 `float` 类型。 + +## typeof + +`typeof(x: any, full_name: bool = False) -> str` + +输出 `x` 在运算时的类型。当 `full_name` 参数设置为 `True` 时,将返回 `pkg.schema` 形式的包前缀。 + +下面是常见的用法: + +```python +import sub as pkg + +_a = 1 + +t1 = typeof(_a) +t2 = typeof("abc") + +schema Person: + name?: any + +_x1 = Person{} +t3 = typeof(_x1) + +_x2 = pkg.Person{} +t4 = typeof(_x2) +t5 = typeof(_x2, full_name=True) + +t6 = typeof(_x1, full_name=True) + +# 输出 +# t1: int +# t2: str +# t3: Person +# t4: Person +# t5: sub.Person +# t6: __main__.Person +``` + +## zip + +`zip(*args: str|list|dict)` + +用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。 + +下面是常见的用法: + +```py +a = zip([0, 1, 2], [3, 4, 5]) +b = zip([0, 1], [3, 4, 5]) +c = zip([0, 1, 2], [3, 4, 5, 6]) + +# 输出 +# a: +# - - 0 +# - 3 +# - - 1 +# - 4 +# - - 2 +# - 5 +# b: +# - - 0 +# - 3 +# - - 1 +# - 4 +# c: +# - - 0 +# - 3 +# - - 1 +# - 4 +# - - 2 +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/crypto.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/crypto.md new file mode 100644 index 000000000..ffde99dc7 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/crypto.md @@ -0,0 +1,139 @@ +--- +title: "crypto" +linkTitle: "crypto" +type: "docs" +description: crypto 包 - 提供 SHA 相关的哈希函数 +weight: 100 +--- + +## md5 + +`md5(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `MD5` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +md5 = crypto.md5("ABCDEF") +``` + +## sha1 + +`sha1(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `SHA1` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +sha = crypto.sha1("ABCDEF") +``` + +## sha224 + +`sha224(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `SHA224` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +sha = crypto.sha224("ABCDEF") +``` + +## sha256 + +`sha256(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `SHA256` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +sha = crypto.sha256("ABCDEF") +``` + +## sha384 + +`sha384(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `SHA384` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +sha = crypto.sha384("ABCDEF") +``` + +## sha512 + +`sha512(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `SHA512` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +sha = crypto.sha512("ABCDEF") +``` + +## blake3 + +`sha512(value: str, encoding: str = "utf-8") -> str` + +使用注册编码器和 `BLAKE3` 算法对字符串 `value` 进行加密。 + +```python +import crypto + +blake3 = crypto.blake3("ABCDEF") +``` + +## fileblake3 + +`fileblake3(filepath: str) -> str` + +使用注册编码器和 `BLAKE3` 算法对从文件`filepath`读取出的内容进行加密。 + +```python +import crypto + +fileblake3 = crypto.fileblake3("test.txt") +``` + +## uuid + +`uuid() -> str` + +生成一个随机 UUID 字符串。 + +```python +import crypto + +a = crypto.uuid() +``` + +## filesha256 + +`filesha256(filepath: str) -> str` + +计算文件 `filepath` 的 SHA256 哈希。 + +```python +import crypto + +sha = crypto.filesha256("test.txt") +``` + +## filesha512 + +`filesha512(filepath: str) -> str` + +计算文件 `filepath` 的 SHA512 哈希。 + +```python +import crypto + +sha = crypto.filesha512("test.txt") +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/datetime.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/datetime.md new file mode 100644 index 000000000..fae58f413 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/datetime.md @@ -0,0 +1,67 @@ +--- +title: "datetime" +linkTitle: "datetime" +type: "docs" +description: datetime 包 - 时间处理 +weight: 100 +--- + +## ticks + +`ticks() -> float` + +返回从 1970 年 1 月 1 日 0 时 0 分 0 秒(Epoch)开始到当前时间经过的秒数。如果系统时钟能提供更精确的时间,则秒数后可能会有小数部分。 + +```python +import datetime + +ticks = datetime.ticks() +``` + +## date + +`date() -> str` + +返回以 `%Y-%m-%d %H:%M:%S` 格式表示的时间。 + +```python +import datetime + +date = datetime.date() +``` + +## now + +`now(format: str = "%a %b %d %H:%M:%S %Y") -> str` + +返回本地时间格式。例如:`Sat Jun 06 16:26:11 1998`,或者根据指定的格式字符串格式化组合的日期和时间,默认日期格式为 `%a %b %d %H:%M:%S %Y`。 + +```python +import datetime + +date = datetime.now() +``` + +## today + +`today() -> str` + +返回以 `%Y-%m-%d %H:%M:%S.%{ticks}` 格式表示的时间。 + +```python +import datetime + +date = datetime.today() +``` + +## validate + +`validate(date: str, format: str) -> bool` + +验证提供的日期字符串是否与指定格式匹配。 + +```python +import datetime + +result = datetime.validate("2024-08-26", "%Y-%m-%d") # Valid date +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/file.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/file.md new file mode 100644 index 000000000..c194becfa --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/file.md @@ -0,0 +1,175 @@ +--- +title: "file" +linkTitle: "file" +type: "docs" +description: 文件系统操作 +weight: 100 +--- + +## read + +`read(filepath: str) -> str` + +读取文件 `filepath` 中的内容,并返回一个字符串实例。 + +```python +import file + +a = file.read("test.txt") +``` + +## glob + +`glob(pattern: str) -> str` + +返回一个包含所有匹配 `pattern` 的文件名的列表。 + +```python +import file + +json_files = file.glob("./*.json") +``` + +## modpath + +`modpath() -> str` + +返回当前模块的根路径(kcl.mod 文件路径或单个 \*.k 文件路径)。 + +```python +import file + +modpath = file.modpath() +``` + +## workdir + +`workdir() -> str` + +返回当前工作目录的路径。 + +```python +import file + +workdir = file.workdir() +``` + +## exists + +`exists(filepath: str) -> bool` + +判断文件路径是否存在。如果路径指向一个存在的实体,则返回 True。此函数会遍历符号链接以查询目标文件的信息。 + +```python +import file + +file_exists = file.exists("test.txt") +``` + +## abs + +`abs(filepath: str) -> str` + +返回路径的规范化绝对形式,其中所有中间路径均已规范化并解析为符号链接。 + +```python +import file + +abs_file_path = file.abs("test.txt") +``` + +## mkdir + +`mkdir(directory: str, exists: bool=False)` + +如果指定路径上不存在目录,则创建一个新目录。 + +```python +import file + +file.mkdir("path") +``` + +## delete + +`delete(directory: str)` + +在指定路径上删除一个文件或空目录。 + +```python +import file + +file.delete("test.txt") +``` + +## cp + +`cp(src: str, dest: str)` + +将文件或目录从源路径复制到目标路径。 + +```python +import file + +file.cp("src", "dest") +``` + +## mv + +`mv(src: str, dest: str)` + +将文件或目录从源路径移动到目标路径。 + +```python +import file + +file.mv("src", "dest") +``` + +## size + +`size(filepath: str) -> int` + +获取指定路径上文件的大小。 + +```python +import file + +size = file.size("test.txt") +``` + +## write + +`write(filepath: str, content: str)` + +将内容写入指定路径的文件。如果文件不存在,将会被创建。如果文件存在,其内容将被替换。 + +```python +import file + +file.size("test.txt", "content") +``` + +## read_env + +`read_env(key: str) -> str` + +从当前进程中读取环境变量 `key` 的值。 + +```python +import file + +value = file.read_env("ENV_VAR") +``` + +## current + +`current() -> str` + +读取正在执行的当前 KCL 代码文件或模块的路径。 + +```python +import file + +value = file.current() +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/json.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/json.md new file mode 100644 index 000000000..da7a338ee --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/json.md @@ -0,0 +1,111 @@ +--- +title: "json" +linkTitle: "json" +type: "docs" +description: JSON 编码解码 +weight: 100 +--- + +## encode + +```python +encode( + data: any, + sort_keys: bool = False, + indent: int = None, + ignore_private: bool = False, + ignore_none: bool = False +) -> str +``` + +将 KCL 对象 `data` 序列化为 JSON 格式的字符串。 + +```python +import json + +data = { + "key1": "value1" + "key2": "value2" + "data": [1, 2, 3] +} +data_string = json.encode(data) +``` + +## decode + +`decode(value: str) -> any` + +反序列化 `value`(一个包含 JSON 格式文档的字符串实例)为一个 KCL 对象。 + +```python +import file +import json + +data_string = json.decode(file.read(file.modpath()+"/test.json")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data +``` + +## dump_to_file + +```python +dump_to_file( + data: any, + filename: str, + sort_keys: bool = False, + indent: int = None, + ignore_private: bool = False, + ignore_none: bool = False +) -> None +``` + +将 KCL 对象 `data` 序列化为 JSON 格式的字符串,并将其写入文件 `filename` 中。 + +```python +import json + +schema Person: + name?: str + age?: int + school?: str + data?: [int] = [1, 2, None] + +person = Person { + name: "Alice" + age: 18 +} +filename = "out.json" +json.dump_to_file(person, filename, indent=4, ignore_private=True, ignore_none=True) +``` + +## validate + +```python +validate(value: str) -> bool +``` + +验证给定的字符串是否是一个合法的 JSON 字符串。 + +```python +import json + +# Right cases + +resultRight1: bool = json.validate("1") +resultRight2: bool = json.validate("true") +resultRight3: bool = json.validate("1.20") +resultRight4: bool = json.validate("null") +resultRight5: bool = json.validate("[0, 1, 2]") +resultRight6: bool = json.validate('{"key": "value"}') + +# Wrong cases + +resultWrong1: bool = json.validate("1@") +resultWrong2: bool = json.validate("True") +resultWrong3: bool = json.validate("1.20.23+1") +resultWrong4: bool = json.validate("None") +resultWrong5: bool = json.validate("[0, 1, 2,]") +resultWrong6: bool = json.validate(r'''{"key": 'value'}''') +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/manifests.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/manifests.md new file mode 100644 index 000000000..5c54e9c76 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/manifests.md @@ -0,0 +1,89 @@ +--- +title: "manifests" +linkTitle: "manifests" +type: "docs" +description: manifests system module +weight: 100 +--- + +## yaml_stream + +```python +yaml_stream(values: [any], opts: {str:} = { + sort_keys = False + ignore_private = True + ignore_none = False + sep = "---" +}) +``` + +这个函数的功能是将 KCL 对象列表序列化为带 `---` 分隔符的样式 YAML 输出,它具有两个参数: + +- `values` - 一个 KCL 对象列表 +- `opts` - YAML 序列化选项 + - `sort_keys`:是否按属性名称的字典序对序列化结果进行排序(默认为 `False`)。 + - `ignore_private`:是否忽略名称以 `_` 开头的属性序列化输出(默认为 `True`)。 + - `ignore_none`:是否忽略值为 `None` 的属性(默认为 `False`)。 + - `sep`:在多个 YAML 文档之间选择怎样的分隔符(默认为 `"---"`)。 + +下面我们通过一个例子来说明: + +```python +# 使用 `import` 关键词导入 `manifests` 模块 +import manifests + +# `Deployment` schema 定义 +schema Deployment: + apiVersion: str = "v1" + kind: str = "Deployment" + metadata: {str:} = { + name = "deploy" + } + spec: {str:} = { + replica = 2 + } + +# `Service` schema 定义 +schema Service: + apiVersion: str = "v1" + kind: str = "Service" + metadata: {str:} = { + name = "svc" + } + spec: {str:} = {} + +# 定义两个 `Deployment` 资源 +deployments = [Deployment {}, Deployment {}] +# 定义两个 `Service` 资源 +services = [Service {}, Service {}] +# 将它们放入 KCL 列表,并调用 `manifests.yaml_stream` 函数。 +manifests.yaml_stream(deployments + services) +``` + +首先我们通过 `import` 关键字导入 `manifests` 模块并定义 2 个 Deployment 以及 2 个 Service 资源,当我们想以 YAML stream 并以 `---` 作为分隔符的格式依次输出这 4 个资源时,我们可以将它们合并为一个 KCL 列表并作为 `manifests.yaml_stream` 函数的 `values` 形参进行传入 (如无特殊需求,opts 参数一般使用默认值即可),最终得到 YAML 输出为: + +```yaml +apiVersion: v1 +kind: Deployment +metadata: + name: deploy +spec: + replica: 2 +--- +apiVersion: v1 +kind: Deployment +metadata: + name: deploy +spec: + replica: 2 +--- +apiVersion: v1 +kind: Service +metadata: + name: svc +--- +apiVersion: v1 +kind: Service +metadata: + name: svc +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/math.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/math.md new file mode 100644 index 000000000..e16558b27 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/math.md @@ -0,0 +1,216 @@ +--- +title: "math" +linkTitle: "math" +type: "docs" +description: math 包 - 数学函数 +weight: 100 +--- + +## ceil + +`ceil(x) -> int` + +返回 `x` 向上取整得到的整数,这是大于等于 `x` 的最小整数。 + +```python +import math + +a = math.ceil(-45.17) +b = math.ceil(100.12) +``` + +## factorial + +`factorial(x) -> int` + +返回 `x` 的阶乘(即 `x!`),如果 `x` 是负数或者不是整数,则会引发一个错误。 + +```python +import math + +a = math.factorial(5) +``` + +## floor + +`floor(x) -> int` + +返回 `x` 向下取整得到的整数,这是小于等于 `x` 的最大整数。 + +```python +import math + +a = math.floor(-45.17) +b = math.floor(100.12) +``` + +## gcd + +`gcd(a: int, b: int) -> int` + +返回 `x` 和 `y` 的最大公约数。 + +```python +import math + +a = math.gcd(60, 48) +``` + +## isfinite + +`isfinite(x) -> bool` + +如果 `x` 既不是无穷大也不是 `NaN` 返回 `True`,否则返回 `False`。 + +```python +import math + +a = math.isfinite(1) +b = math.isfinite(0) +c = math.isfinite(float("nan")) +``` + +## isinf + +`isinf(x) -> bool` + +如果 `x` 是正无穷或负无穷返回 `True`,否则返回 `False`。 + +```python +import math + +a = math.isinf(1) +b = math.isinf(0) +c = math.isinf(float("nan")) +``` + +## isnan + +`isnan(x) -> bool` + +如果 `x` 是 `NaN` 返回 `True`,否则返回 `False`。 + +```python +import math + +a = math.isnan(1) +b = math.isnan(0) +c = math.isnan(float("nan")) +``` + +## modf + +`modf(x) -> List[float, float]` + +返回 `x` 的整数和小数部分,两个结果均与 `x` 的正负号相同,并且均为浮点数。 + +```python +import math + +a = math.modf(100.12) +b = math.modf(100.72) +``` + +## exp + +`exp(x) -> float` + +返回以 `e` 为底数, `x` 的幂。 + +```python +import math + +a = math.exp(2) +b = math.exp(-6.89) +``` + +## expm1 + +`expm1(x) -> float` + +返回 `e` 的 `x` 次方减去 1,该函数能够避免由于直接计算 `exp(x) - 1` 而引起的精度损失。 + +```python +import math + +a = math.expm1(32) +b = math.expm1(-10.89) +``` + +## log + +`log(x, base=2.71828182845904523536028747135266250) -> float` + +返回以 `e` 为底数,`x` 的对数。 + +```python +import math + +a = math.log10(100) # 2 +``` + +## log1p + +`log1p(x) -> float` + +返回以 `e` 为底数,`1 + x` 的自然对数,该函数能够在 `x` 靠近 0 时精确计算结果。 + +```python +import math + +a = math.log1p(2.7183) +b = math.log1p(2) +c = math.log1p(1) +``` + +## log2 + +`log2(x) -> float` + +返回 `x` 的以 2 为底的对数。 + +```python +import math + +a = math.log2(2.7183) +b = math.log2(2) +c = math.log2(1) +``` + +## log10 + +`log10(x) -> float` + +返回 `x` 的以 10 为底的对数。 + +```python +import math + +a = math.log10(2.7183) +b = math.log10(2) +c = math.log10(1) +``` + +## pow + +`pow(x, y) -> float` + +返回 `x` 的 `y` 次幂(即 `x` 的 `y` 次方)。 + +```python +import math + +a = math.pow(1, 1) +``` + +## sqrt + +`sqrt(x) -> float` + +返回 `x` 的平方根。 + +```python +import math + +a = math.sqrt(9) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/net.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/net.md new file mode 100644 index 000000000..607466db5 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/net.md @@ -0,0 +1,201 @@ +--- +title: "net" +linkTitle: "net" +type: "docs" +description: net 包 - 网络IP处理 +weight: 100 +--- + +## split_host_port + +`split_host_port(ip_end_point: str) -> List[str]` + +从 `ip_end_point` 分离出 `host` 和 `port`。 + +```python +import net + +host_and_port = net.split_host_port("B-K0NZJGH6-0048.local:80") +host_port = net.join_host_port("B-K0NZJGH6-0048.local", 80) +``` + +## join_host_port + +`join_host_port(host, port) -> str` + +合并 `host` 和 `port`。 + +```python +import net + +host_and_port = net.split_host_port("B-K0NZJGH6-0048.local:80") +host_port = net.join_host_port("B-K0NZJGH6-0048.local", 80) +``` + +## fqdn + +`fqdn(name: str = '') -> str` + +返回完全限定域名(FQDN)。 + +```python +import net + +fqdn = net.fqdn() +``` + +## parse_IP + +`parse_IP(ip) -> str` + +将 `ip` 解析为真实的 IP 地址。 + +```python +import net + +ip = net.parse_IP("192.168.0.1") +``` + +## to_IP4 + +`to_IP4(ip) -> str` + +获取 `ip` 的 IPv4 表示形式。 + +```python +import net + +ip = net.to_IP4("192.168.0.1") +``` + +## to_IP16 + +`to_IP16(ip) -> int` + +获取 `ip` 的 IPv6 表示形式。 + +```python +import net + +ip = net.to_IP16("192.168.0.1") +``` + +## IP_string + +`IP_string(ip: str | int) -> str` + +返回 IP 字符串。 + +```python +import net + +ip = net.IP_string("192.168.0.1") +``` + +## is_IPv4 + +`is_IPv4(ip: str) -> bool` + +判断 `ip` 是否为 IPv4。 + +```python +import net + +ip = net.is_IPv4("192.168.0.1") +``` + +## is_IP + +`is_IP(ip: str) -> bool` + +判断 `ip` 是否为有效的 IP 地址。 + +```python +import net + +ip = net.is_IP("192.168.0.1") +``` + +## is_loopback_IP + +`is_loopback_IP(ip: str) -> bool` + +判断 `ip` 是否为回环地址。 + +```python +import net + +isip = net.is_loopback_IP("127.0.0.1") +``` + +## is_multicast_IP + +`is_multicast_IP(ip: str) -> bool` + +判断 `ip` 是否为组播地址。 + +```python +import net + +isip = net.is_multicast_IP("239.255.255.255") +``` + +## is_interface_local_multicast_IP + +`is_interface_local_multicast_IP(ip: str) -> bool` + +判断 `ip` 是否为接口、本地和组播地址。 + +```python +import net + +isip = net.is_interface_local_multicast_IP("239.255.255.255") +``` + +## is_link_local_multicast_IP + +`is_link_local_multicast_IP(ip: str) -> bool` + +判断 `ip` 是否为链路本地和组播地址。 + +```python +import net + +isip = net.is_link_local_multicast_IP("224.0.0.0") +``` + +## is_link_local_unicast_IP + +`is_link_local_unicast_IP(ip: str) -> bool` + +判断 `ip` 是否为链路本地和单播地址。 + +```python +import net + +isip = net.is_link_local_unicast_IP("fe80::2012:1") +``` + +## is_global_unicast_IP + +`is_global_unicast_IP(ip: str) -> bool` + +判断 `ip` 是否为全局单播地址。 + +```python +import net + +isip = net.is_global_unicast_IP("220.181.108.89") +``` + +## is_unspecified_IP + +`is_unspecified_IP(ip: str) -> bool` + +判断 `ip` 是否为 `unspecified` 地址。 + +```python +import net + +isip = net.is_unspecified_IP("0.0.0.0") +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/overview.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/overview.md new file mode 100644 index 000000000..129802224 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/overview.md @@ -0,0 +1,63 @@ +--- +sidebar_position: 0 +--- + +import DocsCard from '@site/src/components/global/DocsCard'; +import DocsCards from '@site/src/components/global/DocsCards'; + +# 概览 + +KCL 通过内置模块、系统库模块和插件模块提供工程化的扩展能力。 + +![](/img/docs/reference/lang/model/kcl-module.png) + +用户代码中不用导入直接使用 builtin 的函数(比如用 `len` 计算列表的长度、通过 `typeof` 获取值的类型等),而对于字符串等基础类型也提供了一些内置方法(比如转化字符串的大小写等方法)。 + +对于相对复杂的通用工作则通过标准库提供,比如通过 import 导入 `math` 库就可以使用相关的数学函数,可以通过导入 `regex` 库使用正则表达式库。 + +## 系统库模块 + + + +

提供了一系列可以直接使用的内置函数

+
+ +

提供了 Base64(RFC 3548)数据编码函数。

+
+ +

提供了常见加密算法和协议的实现。

+
+ +

具体的日期/时间和相关类型和函数。

+
+ +

提供了与 JSON 相关的编码/解码函数。

+
+ +

提供了结构序列化输出 KCL 数据的能力。

+
+ +

提供了常用的数学计算函数。

+
+ +

一个轻量级的 IPv4/IPv6 操作库。

+
+ +

提供了常用的正则表达式函数。

+
+ +

提供了一些数字和国际标准单位之间的转换函数。

+
+ +

提供了与 YAML 相关的编码/解码函数。

+
+ +

提供了与文件系统相关的函数。

+
+ +

提供了与模版相关的函数。

+
+ +

提供了与运行时相关的函数。

+
+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/regex.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/regex.md new file mode 100644 index 000000000..5470831ef --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/regex.md @@ -0,0 +1,79 @@ +--- +title: "regex" +linkTitle: "regex" +type: "docs" +description: regex 包 - 正则表达式 +weight: 100 +--- + +## replace + +`replace(string: str, pattern: str, replace: str, count=0) -> str` + +替换字符串 `string`中最左边、不重叠并且匹配模式 `pattern` 的部分替换为指定的字符串 `replace`,并返回替换后的字符串 + +```python +import regex + +regex_replace = regex.replace(regex_source, ",", "|") +``` + +## match + +`match(string: str, pattern: str) -> bool` + +尝试在字符串开头应用模式 `pattern`,找到了任何匹配项则返回 `True`,返回 `False` 表示没有找到匹配项 + +```python +import regex + +regex_result = regex.match("192.168.0.1", "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$") +``` + +## compile + +`compile(pattern: str) -> bool` + +编译正则表达式模式 `pattern`,并返回一个布尔值,表示该模式是否有效 + +```python +import regex + +regex_compile = regex.compile("$^") +``` + +## findall + +`findall(string: str, pattern: str) -> List[str]` + +查找 `pattern` 在 `string` 中的所有非重叠匹配,并以字符串列表的形式返回 + +```python +import regex + +regex_find_all = regex.findall("aaaa", "a") +``` + +## search + +`search(string: str, pattern: str) -> bool` + +扫描字符串 `string` 以查找与模式匹配的项,如果找到任何匹配项,则返回布尔值 `True`,否则返回 `False` + +```python +import regex + +regex_search = regex.search("aaaa", "a") +``` + +## split + +`split(string: str, pattern: str, maxsplit=0) -> List[str]` + +返回一个由字符串内单词组成的列表,使用 `pattern` 作为分隔字符串,最多进行 `maxsplit` 次拆分 + +```python +import regex + +regex_split = regex.split(regex_source, ",") +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/runtime.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/runtime.md new file mode 100644 index 000000000..3d14e4cc0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/runtime.md @@ -0,0 +1,30 @@ +--- +title: "runtime" +linkTitle: "runtime" +type: "docs" +description: 运行时函数 +weight: 100 +--- + +## catch + +`catch(func: () -> any) -> str` + +`catch` 函数可以执行代码块并捕获任何潜在的运行时错误。如果代码块中没有发生异常,`catch` 函数返回 `Undefined`,否则返回异常信息。 + +```python +import runtime + +schema Person: + name: str + age: int + + check: + 0 <= age <= 120, "age must be in [1, 120], got ${age}" + +test_person_check_error = lambda { + assert runtime.catch(lambda { + p = Person {name = "Alice", age: -1} + }) == "age must be in [1, 120], got -1" +} +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/template.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/template.md new file mode 100644 index 000000000..65c58dbf7 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/template.md @@ -0,0 +1,48 @@ +--- +title: "template" +linkTitle: "template" +type: "docs" +description: 模版操作 +weight: 100 +--- + +## execute + +`execute(template: str, data: {str:any} = {}) -> str` + +将解析过的模板应用于指定的数据对象,并返回字符串输出。查看 https://handlebarsjs.com/ 获取更多文档和示例。 + +```python +import template + +content = template.execute("""\ +
+{{#if author}} +

{{firstName}} {{lastName}}

+{{/if}} +
+""", { + author: True, + firstName: "Yehuda", + lastName: "Katz", +}) +``` + +## html_escape + +`html_escape(data: str) -> str` + +将字符 `&"<>` 替换为等效的 html / xml实体。 + +```python + +import template + +content = template.html_escape("""\ +
+{{#if author}} +

{{firstName}} {{lastName}}

+{{/if}} +
+""") +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/units.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/units.md new file mode 100644 index 000000000..ccc10c495 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/units.md @@ -0,0 +1,60 @@ +--- +title: "units" +linkTitle: "units" +type: "docs" +description: units 包 - 单位处理 +weight: 100 +--- + +## 单位的常量 + +- 定点数: `n`, `u`, `m`, `k`, `K`, `G`, `T` 和 `P`. +- 2 的幂: `Ki`, `Mi`, `Gi`, `Ti` 和 `Pi`. + +## 函数列表 + +- `to_n(num: int) -> str` + 将 int 转换为以 `n` 作为后缀的字符串 +- `to_u(num: int) -> str` + 将 int 转换为以 `u` 作为后缀的字符串 +- `to_m(num: int) -> str` + 将 int 转换为以 `m` 作为后缀的字符串 +- `to_K(num: int) -> str` + 将 int 转换为以 `K` 作为后缀的字符串 +- `to_M(num: int) -> str` + 将 int 转换为以 `M` 作为后缀的字符串 +- `to_G(num: int) -> str` + 将 int 转换为以 `G` 作为后缀的字符串 +- `to_T(num: int) -> str` + 将 int 转换为以 `T` 作为后缀的字符串 +- `to_P(num: int) -> str` + 将 int 转换为以 `P` 作为后缀的字符串 +- `to_Ki(num: int) -> str` + 将 int 转换为以 `Ki` 作为后缀的字符串 +- `to_Mi(num: int) -> str` + 将 int 转换为以 `Mi` 作为后缀的字符串 +- `to_Gi(num: int) -> str` + 将 int 转换为以 `Gi` 作为后缀的字符串 +- `to_Ti(num: int) -> str` + 将 int 转换为以 `Ti` 作为后缀的字符串 +- `to_Pi(num: int) -> str` + 将 int 转换为以 `Pi` 作为后缀的字符串 + +```python +import units +# SI +n = units.to_n(1e-9) +u = units.to_u(1e-6) +m = units.to_m(1e-1) +K = units.to_K(1000) +M = units.to_M(1000000) +G = units.to_G(1000000000) +T = units.to_T(1000000000000) +P = units.to_P(1000000000000000) +# IEC +Ki = units.to_Ki(1024) +Mi = units.to_Mi(1024 ** 2) +Gi = units.to_Gi(1024 ** 3) +Ti = units.to_Ti(1024 ** 4) +Pi = units.to_Pi(1024 ** 5) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/yaml.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/yaml.md new file mode 100644 index 000000000..a1df604f7 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/model/yaml.md @@ -0,0 +1,173 @@ +--- +title: "yaml" +linkTitle: "yaml" +type: "docs" +description: yaml 编码解码 +weight: 300 +--- + +## encode + +```python +encode( + data: any, + sort_keys: bool = False, + ignore_private: bool = False, + ignore_none: bool = False +) -> str +``` + +将 KCL 对象 `data` 序列化为 YAML 格式的字符串。 + +```python +import yaml + +data = { + "key1": "value1" + "key2": "value2" + "data": [1, 2, 3] +} +data_string = yaml.encode(data) +``` + +## encode_all + +```python +encode( + data: [any], + sort_keys: bool = False, + ignore_private: bool = False, + ignore_none: bool = False +) -> str +``` + +将 KCL 对象列表 `data` 序列化为包含 `---` 分隔符的 YAML Stream 格式的字符串。 + +```python +import yaml + +yamlStr = yaml.encode_all([1, 2, 3]) +``` + +## decode + +`decode(value: str) -> any` + +反序列化 `value`(一个包含 YAML 格式文档的字符串实例)为一个 KCL 对象。 + +```python +import yaml +import file + +data_string = yaml.decode(file.read("test.yaml")) + +key1 = data_string.key1 +key2 = data_string.key2 +data = data_string.data +``` + +## decode_all + +`decode_all(value: str) -> [any]` + +反序列化 `value`(一个包含 `---` 分隔符的 YAML Stream 格式文档的字符串实例)为一个 KCL 对象列表。 + +```python +import yaml + +yamlStr = """\ +key: value +""" +data = yaml.decode(yamlStr) +dataList = yaml.decode_all(yamlStr) +``` + +## dump_to_file + +```python +dump_to_file( + data: any, + filename: str, + sort_keys: bool = False, + ignore_private: bool = False, + ignore_none: bool = False +) -> None +``` + +将 KCL 对象 `data` 序列化为 YAML 格式的字符串,并将其写入文件 `filename` 中。 + +```python +import yaml + +schema Person: + name?: str + age?: int + school?: str + data?: [int] = [1, 2, None] + +person = Person { + name: "Alice" + age: 18 +} +filename = "out.yaml" +yaml.dump_to_file(person, filename, ignore_private=True, ignore_none=True) +``` + +## dump_all_to_file + +```python +dump_all_to_file( + data: [any], + filename: str, + ignore_private: bool = False, + ignore_none: bool = False +) -> None +``` + +将 KCL 对象列表序列化为 YAML Stream 格式,并将其写入文件 `filename` 中。 + +```python +import yaml + +yamlStrList = [ + 'key: value', + '- 1\n- 2\n- 3', + '1', + '1.1', + 'null', + 'true', +] +yaml.dump_all_to_file(yamlStrList, "0.yaml") +``` + +## validate + +```python +validate(value: str) -> bool +``` + +验证给定的字符串是否是一个合法的 YAML 或者 YAML Stream 格式的字符串。 + +```python +import yaml + +# Right cases + +resultRight1: bool = yaml.validate("1") +resultRight2: bool = yaml.validate("true") +resultRight3: bool = yaml.validate("1.20") +resultRight4: bool = yaml.validate("null") +resultRight5: bool = yaml.validate("[0, 1, 2]") +resultRight6: bool = yaml.validate('{"key": "value"}') +resultRight7: bool = yaml.validate('a:1\n---\nb:2') + +# Wrong cases + +resultWrong1: bool = yaml.validate("a:\n1") +resultWrong2: bool = yaml.validate("a:\n1\n - 2") +resultWrong3: bool = yaml.validate("a:\n-1") +resultWrong4: bool = yaml.validate("1a : \n1") +resultWrong5: bool = yaml.validate("a:\n- 1\n-----\na:\n- 1") +resultWrong6: bool = yaml.validate(r'''{"key" + 'value'}''') +resultWrong7: bool = yaml.validate("a:1\n-----\nb:\n-2") +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/_category_.json new file mode 100644 index 000000000..5a687a08b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "插件系统", + "position": 5 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/overview.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/overview.md new file mode 100644 index 000000000..edb3ce7ec --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/plugin/overview.md @@ -0,0 +1,249 @@ +--- +sidebar_position: 1 +--- + +# 简介 + +KCL 是声明式配置策略语言,对于不方便通过配置直接描述的复杂的业务逻辑可以通过通用的编程语言开发 KCL 插件对语言进行扩展。KCL 支持通过通用语言开发插件,KCL 程序导入插件中的函数。KCL 通过插件运行时和辅助的命令行工具提供插件支持。KCL 插件框架目前支持 Python 语言和 Go 语言开发插件。 + +插件的 Git 仓库: [https://github.com/kcl-lang/kcl-plugin](https://github.com/kcl-lang/kcl-plugin) + +## 使用 Go 编写插件 + +### 0. 前置依赖 + +使用 KCL Go 插件需要您的 `PATH` 中存在 `Go 1.21+` 并在 Go 代码中添加 KCL Go SDK 的依赖 + +### 1. 你好插件 + +编写如下 Go 代码并添加你好插件的依赖 + +```go +package main + +import ( + "fmt" + + "kcl-lang.io/kcl-go/pkg/kcl" // Import the native API + _ "kcl-lang.io/kcl-go/pkg/plugin/hello_plugin" // Import the hello plugin +) + +func main() { + yaml := kcl.MustRun("main.k", kcl.WithCode(code)).GetRawYamlResult() + fmt.Println(yaml) +} + +const code = ` +import kcl_plugin.hello + +name = "kcl" +three = hello.add(1,2) # hello.add is written by Go +` +``` + +在 KCL 代码中,可以通过 `kcl_plugin.hello` 导入 `hello` 插件。运行上述代码可以得到如下输出结果 + +```yaml +name: kcl +three: 3 +``` + +### 2. 插件结构 + +KCL Go 插件本质上是一个简单的 Go 工程,主要包含插件代码的 Go 文件 `api.go`,其中定义了插件的注册以及实现函数 + +```go +package hello_plugin + +import ( + "kcl-lang.io/kcl-go/pkg/plugin" +) + +func init() { + plugin.RegisterPlugin(plugin.Plugin{ + Name: "hello", + MethodMap: map[string]plugin.MethodSpec{ + "add": { + Body: func(args *plugin.MethodArgs) (*plugin.MethodResult, error) { + v := args.IntArg(0) + args.IntArg(1) + return &plugin.MethodResult{V: v}, nil + }, + }, + }, + }) +} +``` + +### 3. 插件测试 + +编写 `api_test.go` 文件对插件函数进行单元测试 + +```go +package hello_plugin + +import ( + "testing" + + "kcl-lang.io/kcl-go/pkg/plugin" +) + +func TestPluginAdd(t *testing.T) { + result_json := plugin.Invoke("kcl_plugin.hello.add", []interface{}{111, 22}, nil) + if result_json != "133" { + t.Fatal(result_json) + } +} +``` + +## 使用 Python 编写插件 + +### 0. 先决条件 + +使用 KCL Python 插件需要在您的 PATH 中具有 Python 3.7+,并安装 KCL Python SDK。 + +```shell +python3 -m pip install kcl_lib +``` + +### 1. 你好插件 + +编写以下 Python 代码并添加名为 `my_plugin` 的插件。 + +```python +import kcl_lib.plugin as plugin +import kcl_lib.api as api + +plugin.register_plugin("my_plugin", {"add": lambda x, y: x + y}) + +def main(): + result = api.API().exec_program( + api.ExecProgram_Args(k_filename_list=["test.k"]) + ) + assert result.yaml_result == "result: 2" + +main() +``` + +test.k 的内容为: + +```python +import kcl_plugin.my_plugin + +result = my_plugin.add(1, 1) +``` + +## 使用 Java 编写插件 + +### 0. 先决条件 + +使用 KCL Java 插件需要在您的 PATH 中具有 Java 8+,并安装 KCL Java SDK。 + +### 1. 你好插件 + +编写以下 Java 代码并添加名为 `my_plugin` 的插件。 + +```java +package com.kcl; + +import com.kcl.api.API; +import com.kcl.api.Spec.ExecProgram_Args; +import com.kcl.api.Spec.ExecProgram_Result; +import java.util.Collections; + +public class PluginTest { + public static void main(String[] mainArgs) throws Exception { + API.registerPlugin("my_plugin", Collections.singletonMap("add", (args, kwArgs) -> { + return (int) args[0] + (int) args[1]; + })); + + API api = new API(); + ExecProgram_Result result = api + .execProgram(ExecProgram_Args.newBuilder().addKFilenameList("test.k").build()); + System.out.println(result.getYamlResult()); + } +} +``` + +test.k 的内容为: + +```python +import kcl_plugin.my_plugin + +result = my_plugin.add(1, 1) +``` + +## 使用 Rust 编写插件 + +### 0. 先决条件 + +使用 KCL Rust 插件需要在您的 PATH 中具有 Rust 1.79+,并安装 KCL Rust SDK。 + +```shell +cargo add anyhow +cargo add kclvm-parser --git https://github.com/kcl-lang/kcl +cargo add kclvm-loader --git https://github.com/kcl-lang/kcl +cargo add kclvm-evaluator --git https://github.com/kcl-lang/kcl +cargo add kclvm-runtime --git https://github.com/kcl-lang/kcl +``` + +### 1. 你好插件 + +编写以下 Rust 代码并添加名为 `my_plugin` 的插件。 + +```rust +use anyhow::{anyhow, Result}; +use kclvm_evaluator::Evaluator; +use kclvm_loader::{load_packages, LoadPackageOptions}; +use kclvm_parser::LoadProgramOptions; +use kclvm_runtime::{Context, IndexMap, PluginFunction, ValueRef}; +use std::{cell::RefCell, rc::Rc, sync::Arc}; + +fn my_plugin_sum(_: &Context, args: &ValueRef, _: &ValueRef) -> Result { + let a = args + .arg_i_int(0, Some(0)) + .ok_or(anyhow!("expect int value for the first param"))?; + let b = args + .arg_i_int(1, Some(0)) + .ok_or(anyhow!("expect int value for the second param"))?; + Ok((a + b).into()) +} + +fn context_with_plugin() -> Rc> { + let mut plugin_functions: IndexMap = Default::default(); + let func = Arc::new(my_plugin_sum); + plugin_functions.insert("my_plugin.add".to_string(), func); + let mut ctx = Context::new(); + ctx.plugin_functions = plugin_functions; + Rc::new(RefCell::new(ctx)) +} + +fn main() -> Result<()> { + let src = r#" +import kcl_plugin.my_plugin + +sum = my_plugin.add(1, 1) +"#; + let p = load_packages(&LoadPackageOptions { + paths: vec!["test.k".to_string()], + load_opts: Some(LoadProgramOptions { + load_plugins: true, + k_code_list: vec![src.to_string()], + ..Default::default() + }), + load_builtin: false, + ..Default::default() + })?; + let evaluator = Evaluator::new_with_runtime_ctx(&p.program, context_with_plugin()); + let result = evaluator.run()?; + println!("yaml result {}", result.1); + Ok(()) +} +``` + +test.k 的内容为: + +```python +import kcl_plugin.my_plugin + +result = my_plugin.add(1, 1) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/_category_.json new file mode 100644 index 000000000..c2aafb213 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Multi-Language", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/c-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/c-api.md new file mode 100644 index 000000000..7ffc812db --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/c-api.md @@ -0,0 +1,172 @@ +--- +sidebar_position: 10 +--- + +# C API + +The [C API](https://github.com/kcl-lang/lib/tree/main/c) is in the development stage and contributions are welcome. + +## Prerequisites + +- Make +- C Compiler +- Cargo + +## API Reference + +### exec_program + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +```c +#include + +int exec_file(const char* file_str) { + uint8_t buffer[BUFFER_SIZE]; + uint8_t result_buffer[BUFFER_SIZE]; + size_t message_length; + bool status; + struct Buffer file = { + .buffer = file_str, + .len = strlen(file_str), + }; + struct Buffer* files[] = { &file }; + struct RepeatedString strs = { .repeated = &files[0], .index = 0, .max_size = 1 }; + ExecProgramArgs args = ExecProgramArgs_init_zero; + args.k_filename_list.funcs.encode = encode_str_list; + args.k_filename_list.arg = &strs; + + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + status = pb_encode(&stream, ExecProgramArgs_fields, &args); + message_length = stream.bytes_written; + + if (!status) { + printf("Encoding failed: %s\n", PB_GET_ERROR(&stream)); + return 1; + } + + const char* api_str = "KclService.ExecProgram"; + size_t result_length = call_native((const uint8_t*)api_str, strlen(api_str), buffer, message_length, result_buffer); + if (check_error_prefix(result_buffer)) { + printf("%s", result_buffer); + return 1; + } + pb_istream_t istream = pb_istream_from_buffer(result_buffer, result_length); + + ExecProgramResult result = ExecProgramResult_init_default; + + uint8_t yaml_value_buffer[BUFFER_SIZE] = { 0 }; + result.yaml_result.arg = yaml_value_buffer; + result.yaml_result.funcs.decode = decode_string; + + uint8_t json_value_buffer[BUFFER_SIZE] = { 0 }; + result.json_result.arg = json_value_buffer; + result.json_result.funcs.decode = decode_string; + + uint8_t err_value_buffer[BUFFER_SIZE] = { 0 }; + result.err_message.arg = err_value_buffer; + result.err_message.funcs.decode = decode_string; + + uint8_t log_value_buffer[BUFFER_SIZE] = { 0 }; + result.log_message.arg = log_value_buffer; + result.log_message.funcs.decode = decode_string; + + status = pb_decode(&istream, ExecProgramResult_fields, &result); + + if (!status) { + printf("Decoding failed: %s\n", PB_GET_ERROR(&istream)); + return 1; + } + + if (result.yaml_result.arg) { + printf("%s\n", (char*)result.yaml_result.arg); + } + + return 0; +} + +int main() +{ + exec_file("./test_data/schema.k"); + return 0; +} +``` + +

+
+ +### validate_code + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +```c +#include + +int validate(const char* code_str, const char* data_str) +{ + uint8_t buffer[BUFFER_SIZE]; + uint8_t result_buffer[BUFFER_SIZE]; + size_t message_length; + bool status; + + ValidateCodeArgs validate_args = ValidateCodeArgs_init_zero; + validate_args.code.funcs.encode = encode_string; + validate_args.code.arg = (void*)code_str; + validate_args.data.funcs.encode = encode_string; + validate_args.data.arg = (void*)data_str; + + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + status = pb_encode(&stream, ValidateCodeArgs_fields, &validate_args); + message_length = stream.bytes_written; + + if (!status) { + printf("Encoding failed: %s\n", PB_GET_ERROR(&stream)); + return 1; + } + + const char* api_str = "KclService.ValidateCode"; + size_t result_length = call_native((const uint8_t*)api_str, strlen(api_str), buffer, message_length, result_buffer); + pb_istream_t istream = pb_istream_from_buffer(result_buffer, result_length); + ValidateCodeResult result = ValidateCodeResult_init_default; + + result.err_message.funcs.decode = decode_string; + uint8_t value_buffer[BUFFER_SIZE] = { 0 }; + result.err_message.arg = value_buffer; + + status = pb_decode(&istream, ValidateCodeResult_fields, &result); + + if (!status) { + printf("Decoding failed: %s\n", PB_GET_ERROR(&istream)); + return 1; + } + + printf("Validate Status: %d\n", result.success); + if (result.err_message.arg) { + printf("Validate Error Message: %s\n", (char*)result.err_message.arg); + } + return 0; +} + +int main() +{ + const char* code_str = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + " 0 < age < 120\n"; + const char* data_str = "{\"name\": \"Alice\", \"age\": 10}"; + const char* error_data_str = "{\"name\": \"Alice\", \"age\": 1110}"; + validate(code_str, data_str); + validate(code_str, error_data_str); + return 0; +} +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/cpp-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/cpp-api.md new file mode 100644 index 000000000..f6235eabd --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/cpp-api.md @@ -0,0 +1,628 @@ +--- +sidebar_position: 11 +--- + +# C++ API + +The [C++ API](https://github.com/kcl-lang/lib/tree/main/cpp) is in the development stage and contributions are welcome. + +## Prerequisites + +- CMake >= 3.10 +- C++ Compiler with C++17 Support +- Cargo + +## Installation + +### CMake + +You can use FetchContent to add KCL C++ Lib to your project. + +```shell +FetchContent_Declare( + kcl-lib + GIT_REPOSITORY https://github.com/kcl-lang/lib.git + GIT_TAG v0.12.1 # You can change the GitHub branch tag. + SOURCE_SUBDIR cpp +) +FetchContent_MakeAvailable(kcl-lib) +``` + +Or you can download the source code and add it to your project. + +```shell +mkdir third_party +cd third_party +git clone https://github.com/kcl-lang/lib.git +``` + +Update your CMake files. + +```shell +add_subdirectory(third_party/lib/cpp) +``` + +```shell +target_link_libraries(your_target kcl-lib-cpp) +``` + +## API Reference + +### exec_program + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::ExecProgramArgs { + .k_filename_list = { "../test_data/schema.k" }, + }; + auto result = kcl_lib::exec_program(args); + std::cout << result.yaml_result.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### parse_file + +Parse KCL single file to Module AST JSON string with import dependencies and parse errors. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::ParseFileArgs { + .path = "../test_data/schema.k", + }; + auto result = kcl_lib::parse_file(args); + std::cout << result.deps.size() << std::endl; + std::cout << result.errors.size() << std::endl; + std::cout << result.ast_json.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### parse_program + +Parse KCL program with entry files and return the AST JSON string. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::ParseProgramArgs { + .paths = { "../test_data/schema.k" }, + }; + auto result = kcl_lib::parse_program(args); + std::cout << result.paths[0].c_str() << std::endl; + std::cout << result.errors.size() << std::endl; + std::cout << result.ast_json.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### load_package + +load_package provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto parse_args = kcl_lib::ParseProgramArgs { + .paths = { "../test_data/schema.k" }, + }; + auto args = kcl_lib::LoadPackageArgs { + .resolve_ast = true, + }; + args.parse_args = kcl_lib::OptionalParseProgramArgs { + .has_value = true, + .value = parse_args, + }; + auto result = kcl_lib::load_package(args); + std::cout << result.symbols[0].value.ty.value.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### list_variables + +list_variables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::ListVariablesArgs { + .files = { "../test_data/schema.k" }, + }; + auto result = kcl_lib::list_variables(args); + std::cout << result.variables[0].value[0].value.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### list_options + +list_options provides users with the ability to parse KCL program and get all option information. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::ParseProgramArgs { + .paths = { "../test_data/option/main.k" }, + }; + auto result = kcl_lib::list_options(args); + std::cout << result.options[0].name.c_str() << std::endl; + std::cout << result.options[1].name.c_str() << std::endl; + std::cout << result.options[2].name.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### get_schema_type_mapping + +Get schema type mapping defined in the program. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto exec_args = kcl_lib::ExecProgramArgs { + .k_filename_list = { "../test_data/schema.k" }, + }; + auto args = kcl_lib::GetSchemaTypeMappingArgs(); + args.exec_args = kcl_lib::OptionalExecProgramArgs { + .has_value = true, + .value = exec_args, + }; + auto result = kcl_lib::get_schema_type_mapping(args); + std::cout << result.schema_type_mapping[0].key.c_str() << std::endl; + std::cout << result.schema_type_mapping[0].value.properties[0].key.c_str() << std::endl; + std::cout << result.schema_type_mapping[0].value.properties[0].value.ty.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### override_file + +Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::OverrideFileArgs { + .file = { "../test_data/override_file/main.k" }, + .specs = { "b.a=2" }, + }; + auto result = kcl_lib::override_file(args); + std::cout << result.result << std::endl; + std::cout << result.parse_errors.size() << std::endl; + return 0; +} +``` + +

+
+ +### format_code + +Format the code source. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::FormatCodeArgs { + .source = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + " 0 < age < 120\n", + }; + auto result = kcl_lib::format_code(args); + std::cout << result.formatted.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### format_path + +Format KCL file or directory path contains KCL files and returns the changed file paths. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::FormatPathArgs { + .path = "../test_data/format_path/test.k", + }; + auto result = kcl_lib::format_path(args); + std::cout << result.changed_paths.size() << std::endl; + return 0; +} +``` + +

+
+ +### lint_path + +Lint files and return error messages including errors and warnings. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::LintPathArgs { + .paths = { "../test_data/lint_path/test-lint.k" } + }; + auto result = kcl_lib::lint_path(args); + std::cout << result.results[0].c_str() << std::endl; + return 0; +} +``` + +

+
+ +### validate_code + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int validate(const char* code_str, const char* data_str) +{ + auto args = kcl_lib::ValidateCodeArgs { + .code = code_str, + .data = data_str, + }; + auto result = kcl_lib::validate_code(args); + std::cout << result.success << std::endl; + std::cout << result.err_message.c_str() << std::endl; + return 0; +} + +int main() +{ + const char* code_str = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + " 0 < age < 120\n"; + const char* data_str = "{\"name\": \"Alice\", \"age\": 10}"; + const char* error_data_str = "{\"name\": \"Alice\", \"age\": 1110}"; + validate(code_str, data_str); + validate(code_str, error_data_str); + return 0; +} +``` + +Run the ValidateAPI example. + +```shell +./validate_api +``` + +

+
+ +### rename + +Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::RenameArgs { + .package_root = "../test_data/rename", + .symbol_path = "a", + .file_paths = { "../test_data/rename/main.k" }, + .new_name = "a", + }; + auto result = kcl_lib::rename(args); + std::cout << result.changed_files[0].c_str() << std::endl; + return 0; +} +``` + +

+
+ +### rename_code + +Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::RenameCodeArgs { + .package_root = "/mock/path", + .symbol_path = "a", + .source_codes = { { + .key = "/mock/path/main.k", + .value = "a = 1\nb = a\nc = a", + } }, + .new_name = "a2", + }; + auto result = kcl_lib::rename_code(args); + std::cout << result.changed_codes[0].value.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### test + +Test KCL packages with test arguments. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::TestArgs { + .pkg_list = { "../test_data/testing/..." }, + }; + auto result = kcl_lib::test(args); + std::cout << result.info[0].name.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### load_settings_files + +Load the setting file config defined in `kcl.yaml` + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::LoadSettingsFilesArgs { + .work_dir = "../test_data/settings", + .files = { "../test_data/settings/kcl.yaml" }, + }; + auto result = kcl_lib::load_settings_files(args); + std::cout << result.kcl_cli_configs.value.files.size() << std::endl; + std::cout << result.kcl_cli_configs.value.strict_range_check << std::endl; + std::cout << result.kcl_options[0].key.c_str() << std::endl; + std::cout << result.kcl_options[0].value.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### update_dependencies + +Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list. + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +C++ Code + +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::UpdateDependenciesArgs { + .manifest_path = "../test_data/update_dependencies", + }; + auto result = kcl_lib::update_dependencies(args); + std::cout << result.external_pkgs[0].pkg_name.c_str() << std::endl; + std::cout << result.external_pkgs[1].pkg_name.c_str() << std::endl; + return 0; +} +``` + +

+
+ +Call `exec_program` with external dependencies + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +The content of `module/main.k` is + +```cpp +import helloworld +import flask + +a = helloworld.The_first_kcl_program +``` + +C++ Code + +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto args = kcl_lib::UpdateDependenciesArgs { + .manifest_path = "../test_data/update_dependencies", + }; + auto result = kcl_lib::update_dependencies(args); + auto exec_args = kcl_lib::ExecProgramArgs { + .k_filename_list = { "../test_data/update_dependencies/main.k" }, + .external_pkgs = result.external_pkgs, + }; + auto exec_result = kcl_lib::exec_program(exec_args); + std::cout << exec_result.yaml_result.c_str() << std::endl; + return 0; +} +``` + +

+
+ +### get_version + +Return the KCL service version information. + +
Example +

+ +```cpp +#include "kcl_lib.hpp" +#include + +int main() +{ + auto result = kcl_lib::get_version(); + std::cout << result.checksum.c_str() << std::endl; + std::cout << result.git_sha.c_str() << std::endl; + std::cout << result.version.c_str() << std::endl; + std::cout << result.version_info.c_str() << std::endl; + return 0; +} +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/dotnet-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/dotnet-api.md new file mode 100644 index 000000000..de3bef296 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/dotnet-api.md @@ -0,0 +1,614 @@ +--- +sidebar_position: 5 +--- + +# .NET API + +## Installation + +```shell +dotnet add package KclLib +``` + +## Quick Start + +```typescript +using KclLib.API; + +var api = new API(); +var execArgs = new ExecProgramArgs(); +var path = Path.Combine("test_data", "schema.k"); +execArgs.KFilenameList.Add(path); +var result = api.ExecProgram(execArgs); +Console.WriteLine(result.YamlResult); +``` + +## API Reference + +### ExecProgram + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var execArgs = new ExecProgramArgs(); +var path = "schema.k" +execArgs.KFilenameList.Add(path); +var result = new API().ExecProgram(execArgs); +``` + +

+
+ +### ParseFile + +Parse KCL single file to Module AST JSON string with import dependencies and parse errors. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var path = "schema.k" +var args = new ParseFileArgs { Path = path }; +var result = new API().ParseFile(args); +``` + +

+
+ +### ParseProgram + +Parse KCL program with entry files and return the AST JSON string. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var path = "schema.k"; +var args = new ParseProgramArgs(); +args.Paths.Add(path); +var result = new API().ListOptions(args); +``` + +

+
+ +### LoadPackage + +LoadPackage provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var path = "schema.k"; +var args = new LoadPackageArgs(); +args.ResolveAst = true; +args.ParseArgs = new ParseProgramArgs(); +args.ParseArgs.Paths.Add(path); +var result = new API().LoadPackage(args); +``` + +

+
+ +### ListVariables + +ListVariables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var api = new API(); +var args = new ListVariablesArgs(); +var path = "schema.k"; +args.Files.Add(path); +var result = api.ListVariables(args); +``` + +

+
+ +### ListOptions + +ListOptions provides users with the ability to parse KCL program and get all option information. + +
Example +

+ +The content of `options.k` is + +```python +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} +``` + +C# Code + +```csharp +using KclLib.API; + +var path = "options.k"; +var args = new ParseProgramArgs(); +args.Paths.Add(path); +var result = new API().ListOptions(args); +``` + +

+
+ +### GetSchemaTypeMapping + +Get schema type mapping defined in the program. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var path = "schema.k"; +var execArgs = new ExecProgramArgs(); +execArgs.KFilenameList.Add(path); +var args = new GetSchemaTypeMappingArgs(); +args.ExecArgs = execArgs; +var result = new API().GetSchemaTypeMapping(args); +``` + +

+
+ +### OverrideFile + +Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 + +b = { + "a": 1 + "b": 2 +} +``` + +C# Code + +```csharp +using KclLib.API; + +var args = new OverrideFileArgs +{ + File = "main.k", +}; +args.Specs.Add("b.a=2"); +var result = new API().OverrideFile(args); +``` + +

+
+ +### FormatCode + +Format the code source. + +
Example +

+ +C# Code + +```csharp +using KclLib.API; + +string sourceCode = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + + " 0 < age < 120\n"; +string expectedFormattedCode = "schema Person:\n" + " name: str\n" + " age: int\n\n" + " check:\n" + + " 0 < age < 120\n\n"; +var api = new API(); +var args = new FormatCodeArgs(); +args.Source = sourceCode; +var result = api.FormatCode(args); +``` + +

+
+ +### FormatPath + +Format KCL file or directory path contains KCL files and returns the changed file paths. + +
Example +

+ +The content of `format_path.k` is + +```python +schema Person: + name: str + age: int + + check: + 0 < age < 120 +``` + +C# Code + +```csharp +using KclLib.API; + +var api = new API(); +var args = new FormatPathArgs(); +var path = "format_path.k"; +args.Path = path; +var result = api.FormatPath(args); +``` + +

+
+ +### LintPath + +Lint files and return error messages including errors and warnings. + +
Example +

+ +The content of `lint_path.k` is + +```python +import math + +a = 1 +``` + +C# Code + +```csharp +using KclLib.API; + +var path = "lint_path.k" +var args = new LintPathArgs(); +args.Paths.Add(path); +var result = new API().LintPath(args); +bool foundWarning = result.Results.Any(warning => warning.Contains("Module 'math' imported but unused")); +``` + +

+
+ +### ValidateCode + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +C# Code + +```csharp +using KclLib.API; + +string code = @" +schema Person: + name: str + age: int + check: + 0 < age < 120 +"; +string data = "{\"name\": \"Alice\", \"age\": 10}"; +var args = new ValidateCodeArgs +{ + Code = code, + Data = data, + Format = "json" +}; +var result = new API().ValidateCode(args); +``` + +

+
+ +### Rename + +Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 +b = a +``` + +C# Code + +```csharp +using KclLib.API; + +RenameArgs args = RenameArgs.newBuilder().setPackageRoot(".").setSymbolPath("a") + .addFilePaths("main.k").setNewName("a2").build(); +API apiInstance = new API(); +RenameResult result = apiInstance.rename(args); +``` + +

+
+ +### RenameCode + +Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + +
Example +

+ +C# Code + +```csharp +using KclLib.API; + +var args = new RenameCodeArgs +{ + PackageRoot = "/mock/path", + SymbolPath = "a", + SourceCodes = { { "/mock/path/main.k", "a = 1\nb = a" } }, + NewName = "a2" +}; +var result = new API().RenameCode(args); +``` + +

+
+ +### Test + +Test KCL packages with test arguments. + +
Example +

+ +C# Code + +```csharp +using KclLib.API; + +var pkg = Path.Combine(parentDirectory, "test_data", "testing"); +var args = new TestArgs(); +args.PkgList.Add(pkg + "/..."); +var result = new API().Test(args); +``` + +

+
+ +### LoadSettingsFiles + +Load the setting file config defined in `kcl.yaml` + +
Example +

+ +The content of `kcl.yaml` is + +```yaml +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value +``` + +C# Code + +```csharp +using KclLib.API; + +var workDir = "."; +var settingsFile = "kcl.yaml"; +var args = new LoadSettingsFilesArgs +{ + WorkDir = workDir, +}; +args.Files.Add(settingsFile); +var result = new API().LoadSettingsFiles(args); +``` + +

+
+ +### UpdateDependencies + +Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list. + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +C# Code + +```csharp +using KclLib.API; + +var manifestPath = "module"; +var args = new UpdateDependenciesArgs { ManifestPath = manifestPath }; +var result = new API().UpdateDependencies(args); +``` + +

+
+ +Call `ExecProgram` with external dependencies + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +The content of `module/main.k` is + +```python +import helloworld +import flask + +a = helloworld.The_first_kcl_program +``` + +C# Code + +```csharp +using KclLib.API; + +API api = new API(); + +var manifestPath = "module"; +var testFile = Path.Combine(manifestPath, "main.k"); +var updateArgs = new UpdateDependenciesArgs { ManifestPath = manifestPath }; +var depResult = new API().UpdateDependencies(updateArgs); +var execArgs = new ExecProgramArgs(); +execArgs.KFilenameList.Add(testFile); +execArgs.ExternalPkgs.AddRange(depResult.ExternalPkgs); +var execResult = new API().ExecProgram(execArgs); +``` + +

+
+ +### GetVersion + +Return the KCL service version information. + +
Example +

+ +C# Code + +```csharp +using KclLib.API; + +var result = new API().GetVersion(new GetVersionArgs()); +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/go-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/go-api.md new file mode 100644 index 000000000..3c255e38e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/go-api.md @@ -0,0 +1,1138 @@ +--- +sidebar_position: 3 +--- + +# Go API + + + +```go +import "kcl-lang.io/kcl-go" +``` + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ kcl files │ │ KCL-Go-API │ │ KCLResultList │ +│ ┌───────────┐ │ │ │ │ │ +│ │ 1.k │ │ │ │ │ │ +│ └───────────┘ │ │ │ │ ┌───────────┐ │ ┌───────────────┐ +│ ┌───────────┐ │ │ ┌───────────┐ │ │ │ KCLResult │──┼────────▶│x.Get("a.b.c") │ +│ │ 2.k │ │ │ │ Run(path) │ │ │ └───────────┘ │ └───────────────┘ +│ └───────────┘ │────┐ │ └───────────┘ │ │ │ +│ ┌───────────┐ │ │ │ │ │ ┌───────────┐ │ ┌───────────────┐ +│ │ 3.k │ │ │ │ │ │ │ KCLResult │──┼────────▶│x.Get("k", &v) │ +│ └───────────┘ │ │ │ │ │ └───────────┘ │ └───────────────┘ +│ ┌───────────┐ │ ├───▶│ ┌───────────┐ │──────────▶│ │ +│ │setting.yml│ │ │ │ │RunFiles() │ │ │ ┌───────────┐ │ ┌───────────────┐ +│ └───────────┘ │ │ │ └───────────┘ │ │ │ KCLResult │──┼────────▶│x.JSONString() │ +└─────────────────┘ │ │ │ │ └───────────┘ │ └───────────────┘ + │ │ │ │ │ +┌─────────────────┐ │ │ │ │ ┌───────────┐ │ ┌───────────────┐ +│ Options │ │ │ ┌───────────┐ │ │ │ KCLResult │──┼────────▶│x.YAMLString() │ +│WithOptions │ │ │ │MustRun() │ │ │ └───────────┘ │ └───────────────┘ +│WithOverrides │────┘ │ └───────────┘ │ │ │ +│WithWorkDir │ │ │ │ │ +│WithDisableNone │ │ │ │ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ +``` + +
Example +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + const k_code = ` +name = "kcl" +age = 1 + +two = 2 + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {} +x1 = Person { + age = 101 +} +` + + yaml := kcl.MustRun("testdata/main.k", kcl.WithCode(k_code)).First().YAMLString() + fmt.Println(yaml) + + fmt.Println("----") + + result := kcl.MustRun("./testdata/main.k").First() + fmt.Println(result.JSONString()) + + fmt.Println("----") + fmt.Println("x0.name:", result.Get("x0.name")) + fmt.Println("x1.age:", result.Get("x1.age")) + + fmt.Println("----") + + var person struct { + Name string + Age int + } + fmt.Printf("person: %+v\n", result.Get("x1", &person)) +} +``` + +

+
+ + +## Constants + +KclAbiVersion is the current kcl ABI version. + +```go +const KclAbiVersion = scripts.KclAbiVersion +``` + +## func [FormatCode](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L156) + +```go +func FormatCode(code interface{}) ([]byte, error) +``` + +FormatCode returns the formatted code. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + out, err := kcl.FormatCode(`a = 1+2`) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(out)) + +} +``` + +``` +a = 1 + 2 +``` + +

+
+ +## func [FormatPath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L168) + +```go +func FormatPath(path string) (changedPaths []string, err error) +``` + +FormatPath formats files from the given path path: if path is \`.\` or empty string, all KCL files in current directory will be formatted, not recursively if path is \`path/file.k\`, the specified KCL file will be formatted if path is \`path/to/dir\`, all KCL files in the specified dir will be formatted, not recursively if path is \`path/to/dir/...\`, all KCL files in the specified dir will be formatted recursively + +the returned changedPaths are the changed file paths \(relative path\) + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + changedPaths, err := kcl.FormatPath("testdata/fmt") + if err != nil { + log.Fatal(err) + } + fmt.Println(changedPaths) +} +``` + +

+
+ +## func [GetSchemaTypeMapping](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L247) + +```go +func GetSchemaTypeMapping(filename string, src any, schemaName string) (map[string]*KclType, error) +``` + +GetSchemaTypeMapping returns a \:\ mapping of schema types from a kcl file or code. + +file: string + +``` +The kcl filename +``` + +code: string + +``` +The kcl code string +``` + +schema_name: string + +``` +The schema name got, when the schema name is empty, all schemas are returned. +``` + + +## func [LintPath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L188) + +```go +func LintPath(paths []string) (results []string, err error) +``` + +LintPath lint files from the given path + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + // import a + // import a # reimport + + results, err := kcl.LintPath([]string{"testdata/lint/import.k"}) + if err != nil { + log.Fatal(err) + } + for _, s := range results { + fmt.Println(s) + } + +} +``` + +``` +Module 'a' is reimported multiple times +Module 'a' imported but unused +Module 'a' imported but unused +``` + +

+
+ +## func [ListDepFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L173) + +```go +func ListDepFiles(workDir string, opt *ListDepFilesOption) (files []string, err error) +``` + +ListDepFiles return the depend files from the given path + +## func [ListDownStreamFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L183) + +```go +func ListDownStreamFiles(workDir string, opt *ListDepsOptions) ([]string, error) +``` + +ListDownStreamFiles return a list of downstream depend files from the given changed path list. + +## func [ListUpStreamFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L178) + +```go +func ListUpStreamFiles(workDir string, opt *ListDepsOptions) (deps []string, err error) +``` + +ListUpStreamFiles return a list of upstream depend files from the given path list + +## func [OverrideFile](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L197) + +```go +func OverrideFile(file string, specs, importPaths []string) (bool, error) +``` + +OverrideFile rewrites a file with override spec file: string. The File that need to be overridden specs: \[\]string. List of specs that need to be overridden. importPaths. List of import statements that need to be added. See https://www.kcl-lang.io/docs/user_docs/guides/automation for more override spec guide. + +## func [Validate](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L208) + +```go +func Validate(dataFile, schemaFile string, opts *ValidateOptions) (ok bool, err error) +``` + +Validate validates the given data file against the specified schema file with the provided options. + +## func [ValidateCode](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L202) + +```go +func ValidateCode(data, code string, opts *ValidateOptions) (ok bool, err error) +``` + +ValidateCode validate data string match code string + +## type [KCLResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L56) + +```go +type KCLResult = kcl.KCLResult +``` + +
Example +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + const k_code = ` +name = "kcl" +age = 1 + +two = 2 + +schema Person: + name: str = "kcl" + age: int = 1 + +x0 = Person {name = "kcl-go"} +x1 = Person {age = 101} +` + + result := kcl.MustRun("testdata/main.k", kcl.WithCode(k_code)).First() + + fmt.Println("x0.name:", result.Get("x0.name")) + fmt.Println("x1.age:", result.Get("x1.age")) + +} +``` + +``` +x0.name: kcl-go +x1.age: 101 +``` + +

+
+ +
Example (Get) +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + const k_code = ` +schema Person: + name: str = "kcl" + age: int = 1 + X: int = 2 + +x = { + "a": Person {age = 101} + "b": 123 +} +` + + result := kcl.MustRun("testdata/main.k", kcl.WithCode(k_code)).First() + + var person struct { + Name string + Age int + } + fmt.Printf("person: %+v\n", result.Get("x.a", &person)) + fmt.Printf("person: %+v\n", person) + +} +``` + +``` +person: &{Name:kcl Age:101} +person: {Name:kcl Age:101} +``` + +

+
+ +## type [KCLResultList](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L57) + +```go +type KCLResultList = kcl.KCLResultList +``` + +### func [MustRun](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L74) + +```go +func MustRun(path string, opts ...Option) *KCLResultList +``` + +MustRun is like Run but panics if return any error. + +
Example +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + yaml := kcl.MustRun("testdata/main.k", kcl.WithCode(`name = "kcl"`)).First().YAMLString() + fmt.Println(yaml) + +} +``` + +``` +name: kcl +``` + +

+
+ +
Example (Raw Yaml) +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + const code = ` +b = 1 +a = 2 +` + yaml := kcl.MustRun("testdata/main.k", kcl.WithCode(code)).GetRawYamlResult() + fmt.Println(yaml) + + yaml_sorted := kcl.MustRun("testdata/main.k", kcl.WithCode(code), kcl.WithSortKeys(true)).GetRawYamlResult() + fmt.Println(yaml_sorted) + +} +``` + +``` +b: 1 +a: 2 +a: 2 +b: 1 +``` + +

+
+ +
Example (Schema Type) +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + const code = ` +schema Person: + name: str = "" + +x = Person() +` + json := kcl.MustRun("testdata/main.k", kcl.WithCode(code)).First().JSONString() + fmt.Println(json) + +} +``` + +``` +{ + "x": { + "name": "" + } +} +``` + +

+
+ +
Example (Settings) +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + yaml := kcl.MustRun("./testdata/app0/kcl.yaml").First().YAMLString() + fmt.Println(yaml) +} +``` + +

+
+ +### func [Run](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L79) + +```go +func Run(path string, opts ...Option) (*KCLResultList, error) +``` + +Run evaluates the KCL program with path and opts, then returns the object list. + +### func [RunFiles](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L84) + +```go +func RunFiles(paths []string, opts ...Option) (*KCLResultList, error) +``` + +RunFiles evaluates the KCL program with multi file path and opts, then returns the object list. + +
Example +

+ +```go +package main + +import ( + "fmt" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + result, _ := kcl.RunFiles([]string{"./testdata/app0/kcl.yaml"}) + fmt.Println(result.First().YAMLString()) +} +``` + +

+
+ +## type [KclType](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L59) + +```go +type KclType = kcl.KclType +``` + +### func [GetSchemaType](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L230) + +```go +func GetSchemaType(filename string, src any, schemaName string) ([]*KclType, error) +``` + +GetSchemaType returns schema types from a kcl file or code. + +file: string + +``` +The kcl filename +``` + +code: string + +``` +The kcl code string +``` + +schema_name: string + +``` +The schema name got, when the schema name is empty, all schemas are returned. +``` + +## type [ListDepFilesOption](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L51) + +```go +type ListDepFilesOption = list.Option +``` + +## type [ListDepsOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L50) + +```go +type ListDepsOptions = list.DepOptions +``` + +## type [ListOptionsArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L67) + +```go +type ListOptionsArgs = loader.ListOptionsArgs +``` + +## type [ListOptionsResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L68) + +```go +type ListOptionsResult = loader.ListOptionsResult +``` + +### func [ListOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L269) + +```go +func ListOptions(args *ListOptionsArgs) (*ListOptionsResult, error) +``` + +ListOptions provides users with the ability to parse kcl program and get all option calling information. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + result, err := kcl.ListOptions(&kcl.ListOptionsArgs{ + Paths: []string{"testdata/option/main.k"}, + }) + if err != nil { + log.Fatal(err) + } + fmt.Println(result) +} +``` + +

+
+ +## type [ListVariablesArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L65) + +```go +type ListVariablesArgs = loader.ListVariablesArgs +``` + +## type [ListVariablesResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L66) + +```go +type ListVariablesResult = loader.ListVariablesResult +``` + +### func [ListVariables](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L263) + +```go +func ListVariables(args *ListVariablesArgs) (*ListVariablesResult, error) +``` + +ListVariables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + result, err := kcl.ListVariables(&kcl.ListVariablesArgs{ + Files: []string{"testdata/main.k"}, + }) + if err != nil { + log.Fatal(err) + } + fmt.Println(result) +} +``` + +``` +variables:{key:"age" value:{variables:{value:"2" op_sym:"="}}} variables:{key:"four" value:{variables:{value:"4" op_sym:"="}}} variables:{key:"name" value:{variables:{value:"\"kcl-go\"" op_sym:"="}}} variables:{key:"x0" value:{variables:{value:"Person {}" type_name:"Person" op_sym:"="}}} variables:{key:"x1" value:{variables:{value:"Person {age = 101}" type_name:"Person" op_sym:"=" dict_entries:{key:"age" value:{value:"101" op_sym:"="}}}}} +``` + +

+
+ +## type [LoadPackageArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L63) + +```go +type LoadPackageArgs = loader.LoadPackageArgs +``` + +## type [LoadPackageResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L64) + +```go +type LoadPackageResult = loader.LoadPackageResult +``` + +### func [LoadPackage](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L258) + +```go +func LoadPackage(args *LoadPackageArgs) (*LoadPackageResult, error) +``` + +LoadPackage provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + result, err := kcl.LoadPackage(&kcl.LoadPackageArgs{ + ParseArgs: &kcl.ParseProgramArgs{ + Paths: []string{"testdata/main.k"}, + }, + ResolveAst: true, + }) + if err != nil { + log.Fatal(err) + } + fmt.Println(result) +} +``` + +

+
+ +## type [Option](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L49) + +```go +type Option = kcl.Option +``` + +### func [NewOption](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L89) + +```go +func NewOption() *Option +``` + +NewOption returns a new Option. + +### func [WithCode](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L94) + +```go +func WithCode(codes ...string) Option +``` + +WithCode returns a Option which hold a kcl source code list. + +### func [WithDisableNone](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L123) + +```go +func WithDisableNone(disableNone bool) Option +``` + +WithDisableNone returns a Option which hold a disable none switch. + +### func [WithExternalPkgAndPath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L100) + +```go +func WithExternalPkgAndPath(name, path string) Option +``` + +WithExternalPkgAndPath returns a Option which hold a external package. + +### func [WithExternalPkgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L97) + +```go +func WithExternalPkgs(externalPkgs ...string) Option +``` + +WithExternalPkgs returns a Option which hold a external package list. + +### func [WithFullTypePath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L131) + +```go +func WithFullTypePath(fullTypePath bool) Option +``` + +WithFullTypePath returns a Option which hold a include full type string in the \`\_type\` attribute. + +### func [WithIncludeSchemaTypePath](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L126) + +```go +func WithIncludeSchemaTypePath(includeSchemaTypePath bool) Option +``` + +WithIncludeSchemaTypePath returns a Option which hold a include schema type path switch. + +### func [WithKFilenames](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L105) + +```go +func WithKFilenames(filenames ...string) Option +``` + +WithKFilenames returns a Option which hold a filenames list. + +### func [WithLogger](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L151) + +```go +func WithLogger(l io.Writer) Option +``` + +WithLogger returns a Option which hold a logger. + +### func [WithOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L108) + +```go +func WithOptions(key_value_list ...string) Option +``` + +WithOptions returns a Option which hold a key=value pair list for option function. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + const code = ` +name = option("name") +age = option("age") +` + x, err := kcl.Run("hello.k", kcl.WithCode(code), + kcl.WithOptions("name=kcl", "age=1"), + ) + if err != nil { + log.Fatal(err) + } + + fmt.Println(x.First().YAMLString()) + +} +``` + +``` +age: 1 +name: kcl +``` + +

+
+ +### func [WithOverrides](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L111) + +```go +func WithOverrides(override_list ...string) Option +``` + +WithOverrides returns a Option which hold a override list. + +### func [WithPrintOverridesAST](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L136) + +```go +func WithPrintOverridesAST(printOverridesAST bool) Option +``` + +WithPrintOverridesAST returns a Option which hold a printOverridesAST switch. + +### func [WithSelectors](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L114) + +```go +func WithSelectors(selectors ...string) Option +``` + +WithSelectors returns a Option which hold a path selector list. + +### func [WithSettings](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L117) + +```go +func WithSettings(filename string) Option +``` + +WithSettings returns a Option which hold a settings file. + +### func [WithShowHidden](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L146) + +```go +func WithShowHidden(showHidden bool) Option +``` + +WithShowHidden returns a Option which holds a showHidden switch. + +### func [WithSortKeys](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L141) + +```go +func WithSortKeys(sortKeys bool) Option +``` + +WithSortKeys returns a Option which holds a sortKeys switch. + +### func [WithWorkDir](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L120) + +```go +func WithWorkDir(workDir string) Option +``` + +WithWorkDir returns a Option which hold a work dir. + +## type [ParseProgramArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L69) + +```go +type ParseProgramArgs = parser.ParseProgramArgs +``` + +## type [ParseProgramResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L70) + +```go +type ParseProgramResult = parser.ParseProgramResult +``` + +### func [ParseProgram](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L252) + +```go +func ParseProgram(args *ParseProgramArgs) (*ParseProgramResult, error) +``` + +Parse KCL program with entry files and return the AST JSON string. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" +) + +func main() { + result, err := kcl.ParseProgram(&kcl.ParseProgramArgs{ + Paths: []string{"testdata/main.k"}, + }) + if err != nil { + log.Fatal(err) + } + fmt.Println(result) +} +``` + +

+
+ +## type [TestCaseInfo](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L54) + +```go +type TestCaseInfo = testing.TestCaseInfo +``` + +## type [TestOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L53) + +```go +type TestOptions = testing.TestOptions +``` + +## type [TestResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L55) + +```go +type TestResult = testing.TestResult +``` + +### func [Test](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L213) + +```go +func Test(testOpts *TestOptions, opts ...Option) (TestResult, error) +``` + +Test calls the test tool to run uni tests in packages. + +## type [UpdateDependenciesArgs](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L61) + +```go +type UpdateDependenciesArgs = module.UpdateDependenciesArgs +``` + +## type [UpdateDependenciesResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L62) + +```go +type UpdateDependenciesResult = module.UpdateDependenciesResult +``` + +### func [UpdateDependencies](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L274) + +```go +func UpdateDependencies(args *UpdateDependenciesArgs) (*UpdateDependenciesResult, error) +``` + +Download and update dependencies defined in the kcl.mod file and return the external package name and location list. + +
Example +

+ +```go +package main + +import ( + "fmt" + "log" + + kcl "kcl-lang.io/kcl-go" + "kcl-lang.io/kcl-go/pkg/spec/gpyrpc" +) + +func main() { + // [package] + // name = "mod_update" + // edition = "0.0.1" + // version = "0.0.1" + // + // [dependencies] + // helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } + // flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } + + result, err := kcl.UpdateDependencies(&gpyrpc.UpdateDependenciesArgs{ + ManifestPath: "testdata/update_dependencies", + }) + if err != nil { + log.Fatal(err) + } + + fmt.Println(result) +} +``` + +

+
+ +
Example (Exec Program) +

+ +```go +package main + +import ( + "fmt" + "log" + + "kcl-lang.io/kcl-go/pkg/native" + "kcl-lang.io/kcl-go/pkg/spec/gpyrpc" +) + +func main() { + // [package] + // name = "mod_update" + // edition = "0.0.1" + // version = "0.0.1" + // + // [dependencies] + // helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } + // flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } + + svc := native.NewNativeServiceClient() + + result, err := svc.UpdateDependencies(&gpyrpc.UpdateDependenciesArgs{ + ManifestPath: "testdata/update_dependencies", + }) + if err != nil { + log.Fatal(err) + } + + // import helloworld + // import flask + // a = helloworld.The_first_kcl_program + // fmt.Println(result.ExternalPkgs) + + execResult, err := svc.ExecProgram(&gpyrpc.ExecProgramArgs{ + KFilenameList: []string{"testdata/update_dependencies/main.k"}, + ExternalPkgs: result.ExternalPkgs, + }) + if err != nil { + log.Fatal(err) + } + + fmt.Println(execResult.YamlResult) + +} +``` + +``` +a: Hello World! +``` + +

+
+ +## type [ValidateOptions](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L52) + +```go +type ValidateOptions = validate.ValidateOptions +``` + +## type [VersionResult](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L60) + +```go +type VersionResult = kcl.VersionResult +``` + +### func [GetVersion](https://github.com/kcl-lang/kcl-go/blob/main/kcl.go#L279) + +```go +func GetVersion() (*VersionResult, error) +``` + +GetVersion returns the KCL service version information. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/java-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/java-api.md new file mode 100644 index 000000000..f7d24658a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/java-api.md @@ -0,0 +1,623 @@ +--- +sidebar_position: 5 +--- + +# Java API + +## Installation + +Refer to [this](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages) to configure your Maven; set up your GitHub account and Token in the `settings.xml`. + +### Maven + +In your project's pom.xml, configure our repository as follows: + +```xml + + + github + https://maven.pkg.github.com/kcl-lang/* + + true + + + +``` + +This way you'll be able to import the above dependency to use the SDK. + +```xml + + com.kcl + kcl-lib + 0.12.1 + +``` + +## Quick Start + +```java +import com.kcl.api.API; +import com.kcl.api.Spec.ExecProgramArgs; +import com.kcl.api.Spec.ExecProgramResult; + +public class ExecProgramTest { + public static void main(String[] args) throws Exception { + API api = new API(); + ExecProgramResult result = api + .execProgram(ExecProgramArgs.newBuilder().addKFilenameList("path/to/kcl.k").build()); + System.out.println(result.getYamlResult()); + } +} +``` + +## API Reference + +### execProgram + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; + +ExecProgramArgs args = ExecProgramArgs.newBuilder().addKFilenameList("schema.k").build(); +API apiInstance = new API(); +ExecProgramResult result = apiInstance.execProgram(args); +``` + +

+
+ +### parseFile + +Parse KCL single file to Module AST JSON string with import dependencies and parse errors. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; + +ParseFileArgs args = ParseFileArgs.newBuilder().setPath("schema.k").build(); +API apiInstance = new API(); +ParseFileResult result = apiInstance.parseFile(args); +``` + +

+
+ +### parseProgram + +Parse KCL program with entry files and return the AST JSON string. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; +import com.kcl.ast.*; +import com.kcl.util.JsonUtil; + +API api = new API(); +ParseProgramResult result = api.parseProgram( + ParseProgramArgs.newBuilder().addPaths("path/to/kcl.k").build() +); +System.out.println(result.getAstJson()); +Program program = JsonUtil.deserializeProgram(result.getAstJson()); +``` + +

+
+ +### loadPackage + +loadPackage provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); +LoadPackageResult result = api.loadPackage(LoadPackageArgs.newBuilder().setResolveAst(true) + .setWithAstIndex(true) + .setParseArgs(ParseProgramArgs.newBuilder().addPaths("schema.k").build()).build()); +``` + +

+
+ +### listVariables + +listVariables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); +ListVariablesResult result = api.listVariables( + ListVariablesArgs.newBuilder().setResolveAst(true).setParseArgs( + ParseProgramArgs.newBuilder().addPaths("/path/to/kcl.k").build()) + .build()); +result.getSymbolsMap().values().forEach(s -> System.out.println(s)); +``` + +

+
+ +### listOptions + +listOptions provides users with the ability to parse KCL program and get all option information. + +
Example +

+ +The content of `options.k` is + +```python +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} +``` + +Java Code + +```java +import com.kcl.api.*; + +ParseProgramArgs args = ParseProgramArgs.newBuilder().addPaths("./src/test_data/option/main.k").build(); +API apiInstance = new API(); +ListOptionsResult result = apiInstance.listOptions(args); +``` + +

+
+ +### getSchemaTypeMapping + +Get schema type mapping defined in the program. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; + +ExecProgramArgs execArgs = ExecProgramArgs.newBuilder().addKFilenameList("schema.k").build(); +GetSchemaTypeMappingArgs args = GetSchemaTypeMappingArgs.newBuilder().setExecArgs(execArgs).build(); +API apiInstance = new API(); +GetSchemaTypeMappingResult result = apiInstance.getSchemaTypeMapping(args); +KclType appSchemaType = result.getSchemaTypeMappingMap().get("app"); +String replicasType = appSchemaType.getPropertiesOrThrow("replicas").getType(); +``` + +

+
+ +### overrideFile + +Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 + +b = { + "a": 1 + "b": 2 +} +``` + +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); +String spec = "a=2"; +OverrideFileResult result = api.overrideFile(OverrideFileArgs.newBuilder() + .setFile("./src/test_data/override_file/main.k").addSpecs(spec).build()); +``` + +

+
+ +### formatCode + +Format the code source. + +
Example +

+ +Java Code + +```java +import com.kcl.api.*; + +String sourceCode = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + + " 0 < age < 120\n"; +FormatCodeArgs args = FormatCodeArgs.newBuilder().setSource(sourceCode).build(); +API apiInstance = new API(); +FormatCodeResult result = apiInstance.formatCode(args); +String expectedFormattedCode = "schema Person:\n" + " name: str\n" + " age: int\n\n" + " check:\n" + + " 0 < age < 120\n\n"; +``` + +

+
+ +### formatPath + +Format KCL file or directory path contains KCL files and returns the changed file paths. + +
Example +

+ +The content of `format_path.k` is + +```python +schema Person: + name: str + age: int + + check: + 0 < age < 120 +``` + +Java Code + +```java +import com.kcl.api.*; + +FormatPathArgs args = FormatPathArgs.newBuilder().setPath("format_path.k").build(); +API apiInstance = new API(); +FormatPathResult result = apiInstance.formatPath(args); +Assert.assertTrue(result.getChangedPathsList().isEmpty()); +``` + +

+
+ +### lintPath + +Lint files and return error messages including errors and warnings. + +
Example +

+ +The content of `lint_path.k` is + +```python +import math + +a = 1 +``` + +Java Code + +```java +import com.kcl.api.*; + +LintPathArgs args = LintPathArgs.newBuilder().addPaths("lint_path.k").build(); +API apiInstance = new API(); +LintPathResult result = apiInstance.lintPath(args); +boolean foundWarning = result.getResultsList().stream() + .anyMatch(warning -> warning.contains("Module 'math' imported but unused")); +``` + +

+
+ +### validateCode + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +Java Code + +```java +import com.kcl.api.*; + +String code = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + + " 0 < age < 120\n"; +String data = "{\"name\": \"Alice\", \"age\": 10}"; +ValidateCodeArgs args = ValidateCodeArgs.newBuilder().setCode(code).setData(data).setFormat("json").build(); +API apiInstance = new API(); +ValidateCodeResult result = apiInstance.validateCode(args); +``` + +

+
+ +### rename + +Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 +b = a +``` + +Java Code + +```java +import com.kcl.api.*; + +RenameArgs args = RenameArgs.newBuilder().setPackageRoot(".").setSymbolPath("a") + .addFilePaths("main.k").setNewName("a2").build(); +API apiInstance = new API(); +RenameResult result = apiInstance.rename(args); +``` + +

+
+ +### renameCode + +Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + +
Example +

+ +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); +RenameCodeArgs args = RenameCodeArgs.newBuilder().setPackageRoot("/mock/path").setSymbolPath("a") + .putSourceCodes("/mock/path/main.k", "a = 1\nb = a").setNewName("a2").build(); +RenameCodeResult result = api.renameCode(args); +``` + +

+
+ +### test + +Test KCL packages with test arguments. + +
Example +

+ +Java Code + +```java +import com.kcl.api.*; + +API apiInstance = new API(); +TestArgs args = TestArgs.newBuilder().addPkgList("/path/to/test/package").build(); +TestResult result = apiInstance.test(args); +``` + +

+
+ +### loadSettingsFiles + +Load the setting file config defined in `kcl.yaml` + +
Example +

+ +The content of `kcl.yaml` is + +```yaml +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value +``` + +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); +LoadSettingsFilesArgs args = LoadSettingsFilesArgs.newBuilder().addFiles("kcl.yaml") + .build(); +LoadSettingsFilesResult result = api.loadSettingsFiles(args); +``` + +

+
+ +### updateDependencies + +Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list. + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); + +UpdateDependenciesResult result = api.updateDependencies( + UpdateDependenciesArgs.newBuilder().setManifestPath("module").build()); +``` + +

+
+ +Call `execProgram` with external dependencies + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +The content of `module/main.k` is + +```python +import helloworld +import flask + +a = helloworld.The_first_kcl_program +``` + +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); + +UpdateDependenciesResult result = api.updateDependencies( + UpdateDependenciesArgs.newBuilder().setManifestPath("./src/test_data/update_dependencies").build()); + +ExecProgramArgs execArgs = ExecProgramArgs.newBuilder(). addAllExternalPkgs(result.getExternalPkgsList()) + .addKFilenameList("./src/test_data/update_dependencies/main.k").build(); + +ExecProgramResult execResult = api.execProgram(execArgs); +``` + +

+
+ +### getVersion + +Return the KCL service version information. + +
Example +

+ +Java Code + +```java +import com.kcl.api.*; + +API api = new API(); +GetVersionArgs version_args = GetVersionArgs.newBuilder().build(); +GetVersionResult result = api.getVersion(version_args); +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/kotlin-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/kotlin-api.md new file mode 100644 index 000000000..4403b1097 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/kotlin-api.md @@ -0,0 +1,605 @@ +--- +sidebar_position: 8 +--- + +# Kotlin API + +## Installation + +Refer to [this](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages) to configure your Maven; set up your GitHub account and Token in the `settings.xml`. + +### Maven + +In your project's pom.xml, configure our repository as follows: + +```xml + + + github + https://maven.pkg.github.com/kcl-lang/* + + true + + + +``` + +This way you'll be able to import the above dependency to use the SDK. + +```xml + + com.kcl + kcl-lib-kotlin + 0.12.1 + +``` + +## Quick Start + +```kotlin +import com.kcl.api.API +import com.kcl.api.execProgramArgs + +val args = execProgramArgs { kFilenameList += "schema.k" } +val api = API() +val result = api.execProgram(args) +``` + +## API Reference + +### execProgram + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.execProgramArgs + +val args = execProgramArgs { kFilenameList += "schema.k" } +val api = API() +val result = api.execProgram(args) +``` + +

+
+ +### parseFile + +Parse KCL single file to Module AST JSON string with import dependencies and parse errors. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.parseFileArgs + +val args = parseFileArgs { path = "schema.k" } +val api = API() +val result = api.parseFile(args) +``` + +

+
+ +### loadPackage + +loadPackage provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.loadPackageArgs +import com.kcl.api.parseProgramArgs + +val args = loadPackageArgs { parseArgs = parseProgramArgs { paths += "schema.k" }; resolveAst = true } +val api = API() +val result = api.loadPackage(args) +``` + +

+
+ +### listVariables + +listVariables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.listVariablesArgs + +val args = listVariablesArgs { files += "./src/test_data/schema.k" } +val api = API() +val result = api.listVariables(args) +``` + +

+
+ +### listOptions + +listOptions provides users with the ability to parse KCL program and get all option information. + +
Example +

+ +The content of `options.k` is + +```python +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.parseProgramArgs + +val args = parseProgramArgs { paths += "options.k" } +val api = API() +val result = api.listOptions(args) +``` + +

+
+ +### getSchemaTypeMapping + +Get schema type mapping defined in the program. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.execProgramArgs +import com.kcl.api.getSchemaTypeMappingArgs + +val args = getSchemaTypeMappingArgs { execArgs = execProgramArgs { kFilenameList += "schema.k" } } +val api = API() +val result = api.getSchemaTypeMapping(args) +val appSchemaType = result.schemaTypeMappingMap["app"] ?: throw AssertionError("App schema type not found") +val replicasAttr = appSchemaType.properties["replicas"] ?: throw AssertionError("App schema type of `replicas` not found") +``` + +

+
+ +### overrideFile + +Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 + +b = { + "a": 1 + "b": 2 +} +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.overrideFileArgs + +val api = API() +val result = api.overrideFile( + overrideFileArgs { + file = "main.k"; + specs += spec + } +) +``` + +

+
+ +### formatCode + +Format the code source. + +
Example +

+ +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.formatCodeArgs + +val sourceCode = "schema Person:\n" + + " name: str\n" + + " age: int\n" + + " check:\n" + + " 0 < age < 120\n" +val args = formatCodeArgs { source = sourceCode } +val api = API() +val result = api.formatCode(args) +``` + +

+
+ +### formatPath + +Format KCL file or directory path contains KCL files and returns the changed file paths. + +
Example +

+ +The content of `format_path.k` is + +```python +schema Person: + name: str + age: int + + check: + 0 < age < 120 +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.formatPathArgs + +val args = formatPathArgs { path = "format_path.k" } +val api = API() +val result = api.formatPath(args) +``` + +

+
+ +### lintPath + +Lint files and return error messages including errors and warnings. + +
Example +

+ +The content of `lint_path.k` is + +```python +import math + +a = 1 +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.lintPathArgs + +val args = lintPathArgs { paths += "lint_path.k" } +val api = API() +val result = api.lintPath(args) +``` + +

+
+ +### validateCode + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.validateCodeArgs + +val args = validateCodeArgs { + code = "schema Person:\n" + " name: str\n" + " age: int\n" + " check:\n" + " 0 < age < 120\n" + data = "{\"name\": \"Alice\", \"age\": 10}" +} +val api = API(); +val result = api.validateCode(args); +``` + +

+
+ +### rename + +Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 +b = a +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.renameArgs + +val args = renameArgs { + packageRoot = "." + filePaths += "./main.k" + symbolPath = "a" + newName = "a2" +} +val api = API() +val result = api.rename(args) +``` + +

+
+ +### renameCode + +Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + +
Example +

+ +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.renameCodeArgs + +val api = API() +val args = renameCodeArgs { + packageRoot = "/mock/path" + sourceCodes.put("/mock/path/main.k", "a = 1\nb = a") + symbolPath = "a" + newName = "a2" +} +val result = api.renameCode(args) +``` + +

+
+ +### test + +Test KCL packages with test arguments. + +
Example +

+ +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.testArgs + +val args = testArgs { + pkgList += "/path/to/test/package" +} +val api = API() +val result = api.test(args) +``` + +

+
+ +### loadSettingsFiles + +Load the setting file config defined in `kcl.yaml` + +
Example +

+ +The content of `kcl.yaml` is + +```yaml +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.loadSettingsFilesArgs + +val args = loadSettingsFilesArgs { files += "kcl.yaml" } +val api = API() +val result = api.loadSettingsFiles(args) +``` + +

+
+ +### updateDependencies + +Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list. + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.updateDependenciesArgs + +val api = API() +val args = updateDependenciesArgs { manifestPath = "module" } +val result = api.updateDependencies(args) +``` + +

+
+ +Call `execProgram` with external dependencies + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +The content of `module/main.k` is + +```python +import helloworld +import flask + +a = helloworld.The_first_kcl_program +``` + +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.execProgramArgs +import com.kcl.api.updateDependenciesArgs + +val api = API() +val args = updateDependenciesArgs { manifestPath = "module" } +val result = api.updateDependencies(args) +val execArgs = execProgramArgs { + kFilenameList += "module/main.k" + externalPkgs.addAll(result.externalPkgsList) +} +val execResult = api.execProgram(execArgs) +``` + +

+
+ +### getVersion + +Return the KCL service version information. + +
Example +

+ +Kotlin Code + +```kotlin +import com.kcl.api.API +import com.kcl.api.getVersionArgs + +val api = API() +val args = getVersionArgs {} +val result = api.getVersion(args) +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/lua-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/lua-api.md new file mode 100644 index 000000000..cb73e392f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/lua-api.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 12 +--- + +# Lua API + +The official [Lua KCL package](https://github.com/kcl-lang/lib/tree/main/lua) has not been released yet. Issues and PRs are welcome! + +## Quick Start + +```lua +local result, err = kcl_lib.exec_program({k_filename_list=["schema.k"]}) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/nodejs-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/nodejs-api.md new file mode 100644 index 000000000..9c507d00c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/nodejs-api.md @@ -0,0 +1,590 @@ +--- +sidebar_position: 6 +--- + +# Node.js API + +## Installation + +```shell +npm install kcl-lib +``` + +## Quick Start + +```typescript +import { execProgram, ExecProgramArgs } from "kcl-lib"; + +function main() { + const result = execProgram(new ExecProgramArgs(["path/to/kcl.k"])); + console.log(result.yamlResult); +} + +main(); +``` + +## API Reference + +### execProgram + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Node.js Code + +```ts +import { execProgram, ExecProgramArgs } from "kcl-lib"; + +const result = execProgram(new ExecProgramArgs(["schema.k"])); +``` + +

+
+ +A case with the file not found error + +
Example +

+ +```ts +import { execProgram, ExecProgramArgs } from "kcl-lib"; + +try { + const result = execProgram(new ExecProgramArgs(["file_not_found.k"])); +} catch (error) { + console.log(error.message); +} +``` + +

+
+ +### parseFile + +Parse KCL single file to Module AST JSON string with import dependencies and parse errors. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Node.js Code + +```ts +import { parseFile, ParseFileArgs } from "kcl-lib"; + +const result = parseFile(new ParseFileArgs("schema.k")); +``` + +

+
+ +### parseProgram + +Parse KCL program with entry files and return the AST JSON string. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Node.js Code + +```ts +import { parseProgram, ParseProgramArgs } from "kcl-lib"; + +const result = parseProgram(new ParseProgramArgs(["schema.k"])); +``` + +

+
+ +### loadPackage + +loadPackage provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Node.js Code + +```ts +import { loadPackage, LoadPackageArgs } from "kcl-lib"; + +const result = loadPackage(new LoadPackageArgs(["schema.k"], [], true)); +``` + +

+
+ +### listVariable + +listVariables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Node.js Code + +```ts +import { listVariables, ListVariablesArgs } from "kcl-lib"; + +const result = listVariables(new ListVariablesArgs(["schema.k"], [])); +``` + +

+
+ +### listOptions + +listOptions provides users with the ability to parse KCL program and get all option information. + +
Example +

+ +The content of `options.k` is + +```python +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} +``` + +Node.js Code + +```ts +import { listOptions, ListOptionsArgs } from "kcl-lib"; + +const result = listOptions(new ListOptionsArgs(["options.k"])); +``` + +

+
+ +### getSchemaTypeMapping + +Get schema type mapping defined in the program. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Node.js Code + +```ts +import { getSchemaTypeMapping, GetSchemaTypeMappingArgs } from "kcl-lib"; + +const result = getSchemaTypeMapping(new GetSchemaTypeMappingArgs(["schema.k"])); +``` + +

+
+ +### overrideFile + +Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide. + +
Example +

+ +The content of `main.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig {replicas: 4} +``` + +Node.js Code + +```ts +import { overrideFile, OverrideFileArgs } from "kcl-lib"; + +const result = overrideFile( + new OverrideFileArgs("main.k", ["app.replicas=4"], []), +); +``` + +

+
+ +### formatCode + +Format the code source. + +
Example +

+ +Node.js Code + +```ts +import { formatCode, FormatCodeArgs } from "kcl-lib"; + +const schemaCode = ` +schema Person: + name: str + age: int + + check: + 0 < age < 120 +`; +const result = formatCode(new FormatCodeArgs(schemaCode)); +console.log(result.formatted); +``` + +

+
+ +### formatPath + +Format KCL file or directory path contains KCL files and returns the changed file paths. + +
Example +

+ +The content of `format_path.k` is + +```python +schema Person: + name: str + age: int + + check: + 0 < age < 120 +``` + +Node.js Code + +```ts +import { formatPath, FormatPathArgs } from "kcl-lib"; + +const result = formatPath(new FormatPathArgs("format_path.k")); +``` + +

+
+ +### lintPath + +Lint files and return error messages including errors and warnings. + +
Example +

+ +The content of `lint_path.k` is + +```python +import math + +a = 1 +``` + +Node.js Code + +```ts +import { lintPath, LintPathArgs } from "kcl-lib"; + +const result = lintPath(new LintPathArgs(["lint_path.k"])); +``` + +

+
+ +### validateCode + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +Node.js Code + +```ts +import { validateCode, ValidateCodeArgs } from "kcl-lib"; + +const code = ` +schema Person: + name: str + age: int + + check: + 0 < age < 120 +`; +const data = '{"name": "Alice", "age": 10}'; +const result = validateCode( + new ValidateCodeArgs(undefined, data, undefined, code), +); +``` + +

+
+ +### rename + +Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 +b = a +``` + +Node.js Code + +```ts +import { rename, RenameArgs } from "kcl-lib"; + +const args = new RenameArgs(".", "a", ["main.k"], "a2"); +const result = rename(args); +``` + +

+
+ +### renameCode + +Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + +
Example +

+ +Node.js Code + +```ts +import { renameCode, RenameCodeArgs } from "kcl-lib"; + +const args = RenameCodeArgs( + "/mock/path", + "a", + { "/mock/path/main.k": "a = 1\nb = a" }, + "a2", +); +const result = renameCode(args); +``` + +

+
+ +### test + +Test KCL packages with test arguments. + +
Example +

+ +Node.js Code + +```ts +import { test as kclTest, TestArgs } from "kcl-lib"; + +const result = kclTest(new TestArgs(["/path/to/test/module/..."])); +``` + +

+
+ +### loadSettingsFiles + +Load the setting file config defined in `kcl.yaml` + +
Example +

+ +The content of `kcl.yaml` is + +```yaml +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value +``` + +Node.js Code + +```ts +import { loadSettingsFiles, LoadSettingsFilesArgs } from "kcl-lib"; + +const result = loadSettingsFiles(new LoadSettingsFilesArgs(".", ["kcl.yaml"])); +``` + +

+
+ +### updateDependencies + +Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list. + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +Node.js Code + +```ts +import { updateDependencies, UpdateDependenciesArgs } from "kcl-lib"; + +const result = updateDependencies(new UpdateDependenciesArgs("module", false)); +``` + +

+
+ +Call `execProgram` with external dependencies + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +The content of `module/main.k` is + +```python +import helloworld +import flask + +a = helloworld.The_first_kcl_program +``` + +Node.js Code + +```ts +import { + execProgram, + ExecProgramArgs, + updateDependencies, + UpdateDependenciesArgs, +} from "../index.js"; + +const result = updateDependencies(new UpdateDependenciesArgs("module", false)); +const execResult = execProgram( + new ExecProgramArgs( + ["module/main.k"], + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + result.externalPkgs, + ), +); +``` + +

+
+ +### getVersion + +Return the KCL service version information. + +
Example +

+ +Node.js Code + +```ts +import { getVersion } from "../index.js"; + +const result = getVersion(); +console.log(result.versionInfo); +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/overview.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/overview.md new file mode 100644 index 000000000..8ce491ae2 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/overview.md @@ -0,0 +1,125 @@ +--- +sidebar_position: 1 +--- + +# Introduction + +The KCL language provides multiple general-purpose programming language interfaces, with identical API forms and features. + +## C/Rust APIs + +The core of KCL is developed in Rust, and the C language API is exported externally for packaging and integration in other high-level languages such as Go, Python, etc. + +## REST-API + +The C-API provided by KCL does not have a REST-API. The REST-API is defined by Protobuf. + +### Start REST Service + +The RestAPI service can be started in the following way: + +```shell +kcl server +``` + +The service can then be requested via the POST protocol: + +```shell +curl -X POST http://127.0.0.1:2021/api:protorpc/BuiltinService.Ping --data '{}' +``` + +The output is + +```json +{ + "error": "", + "result": {} +} +``` + +The POST request and the returned JSON data are consistent with the structure defined by Protobuf. + +### `BuiltinService` + +Where the `/api:protorpc/BuiltinService.Ping` path represents the `Ping` method of the `BuiltinService` service. + +The complete `BuiltinService` is defined by Protobuf: + +```protobuf +service BuiltinService { + rpc Ping(PingArgs) returns(PingResult); + rpc ListMethod(ListMethodArgs) returns(ListMethodResult); +} + +message PingArgs { + string value = 1; +} +message PingResult { + string value = 1; +} + +message ListMethodArgs { + // empty +} +message ListMethodResult { + repeated string method_name_list = 1; +} +``` + +The `Ping` method can verify whether the service is normal, and the `ListMethod` method can query the list of all services and functions provided. + +### `KclService` + +The `KclService` service is a service related to KCL functionality. The usage is the same as the `BuiltinService` service. + +For example, there is the following `Person` structure definition: + +```python +schema Person: + key: str + + check: + "value" in key # 'key' is required and 'key' must contain "value" +``` + +Then we want to use `Person` to verify the following JSON data: + +```json +{ "key": "value" } +``` + +This can be done through the `ValidateCode` method of the `KclService` service. Refer to the `ValidateCodeArgs` structure of the `ValidateCode` method: + +```protobuf +message ValidateCodeArgs { + string data = 1; + string code = 2; + string schema = 3; + string attribute_name = 4; + string format = 5; +} +``` + +Construct the JSON data required by the POST request according to the `ValidateCodeArgs` structure, which contains the `Person` definition and the JSON data to be verified: + +```json +{ + "code": "\nschema Person:\n key: str\n\n check:\n \"value\" in key # 'key' is required and 'key' must contain \"value\"\n", + "data": "{\"key\": \"value\"}" +} +``` + +Save this JSON data to the `vet-hello.json` file and verify it with the following command: + +```shell +$ curl -X POST \ + http://127.0.0.1:2021/api:protorpc/KclService.ValidateCode \ + -H "accept: application/json" \ + --data @./vet-hello.json +{ + "error": "", + "result": { + "success": true + } +} +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/python-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/python-api.md new file mode 100644 index 000000000..c8d7064ad --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/python-api.md @@ -0,0 +1,673 @@ +--- +sidebar_position: 4 +--- + +# Python API + +## Installation + +```shell +python3 -m pip install kcl-lib +``` + +## Quick Start + +```typescript +import kcl_lib.api as api + +args = api.ExecProgramArgs(k_filename_list=["path/to/kcl.k"]) +api = api.API() +result = api.exec_program(args) +print(result.yaml_result) +``` + +## API Reference + +### exec_program + +Execute KCL file with arguments and return the JSON/YAML result. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.ExecProgramArgs(k_filename_list=["schema.k"]) +api = api.API() +result = api.exec_program(args) +assert result.yaml_result == "app:\n replicas: 2" +``` + +

+
+ +A case with the file not found error + +
Example +

+ +```python +import kcl_lib.api as api + +try: + args = api.ExecProgramArgs(k_filename_list=["file_not_found"]) + api = api.API() + result = api.exec_program(args) + assert False +except Exception as err: + assert "Cannot find the kcl file" in str(err) +``` + +

+
+ +### parse_file + +Parse KCL single file to Module AST JSON string with import dependencies and parse errors. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.ParseFileArgs(path=TEST_FILE) +api = api.API() +result = api.parse_file(args) +assert len(result.errors) == 0 +``` + +

+
+ +### parse_program + +Parse KCL program with entry files and return the AST JSON string. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.ParseProgramArgs(paths=["schema.k"]) +api = api.API() +result = api.parse_program(args) +assert len(result.paths) == 1 +assert len(result.errors) == 0 +``` + +

+
+ +### load_package + +load_package provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.LoadPackageArgs( + parse_args=api.ParseProgramArgs(paths=["schema.k"]), resolve_ast=True +) +api = api.API() +result = api.load_package(args) +assert list(result.symbols.values())[0].ty.schema_name == "AppConfig" +``` + +

+
+ +### list_variables + +list_variables provides users with the ability to parse KCL program and get all variables by specs. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.ListVariablesArgs(files=[TEST_FILE]) +api = api.API() +result = api.list_variables(args) +assert result.variables["app"].variables[0].value == "AppConfig {replicas: 2}" +``` + +

+
+ +### list_options + +list_options provides users with the ability to parse KCL program and get all option information. + +
Example +

+ +The content of `options.k` is + +```python +a = option("key1") +b = option("key2", required=True) +c = { + metadata.key = option("metadata-key") +} +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.ParseProgramArgs(paths=["options.k"]) +api = api.API() +result = api.list_options(args) +assert len(result.options) == 3 +assert result.options[0].name == "key1" +assert result.options[1].name == "key2" +assert result.options[2].name == "metadata-key" +``` + +

+
+ +### get_schema_type_mapping + +Get schema type mapping defined in the program. + +
Example +

+ +The content of `schema.k` is + +```python +schema AppConfig: + replicas: int + +app: AppConfig { + replicas: 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api + +exec_args = api.ExecProgramArgs(k_filename_list=["schema.k"]) +args = api.GetSchemaTypeMappingArgs(exec_args=exec_args) +api = api.API() +result = api.get_schema_type_mapping(args) +assert result.schema_type_mapping["app"].properties["replicas"].type == "int" +``` + +

+
+ +### override_file + +Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 + +b = { + "a": 1 + "b": 2 +} +``` + +Python Code + +```python +import kcl_lib.api as api +import pathlib + +test_file = "main.k" +args = api.OverrideFileArgs( + file=test_file, + specs=["b.a=2"], +) +api = api.API() +result = api.override_file(args) +assert len(result.parse_errors) == 0 +assert result.result == True +assert pathlib.Path(test_file).read_text() == """\ +a = 1 +b = { + "a": 2 + "b": 2 +} +""" +``` + +

+
+ +### format_code + +Format the code source. + +
Example +

+ +Python Code + +```python +import kcl_lib.api as api + +source_code = """\ +schema Person: + name: str + age: int + + check: + 0 < age < 120 +""" +args = api.FormatCodeArgs(source=source_code) +api_instance = api.API() +result = api_instance.format_code(args) +assert ( + result.formatted.decode() + == """\ +schema Person: + name: str + age: int + + check: + 0 < age < 120 + +""" + ) +``` + +

+
+ +### format_path + +Format KCL file or directory path contains KCL files and returns the changed file paths. + +
Example +

+ +The content of `format_path.k` is + +```python +schema Person: + name: str + age: int + + check: + 0 < age < 120 +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.FormatPathArgs(path="format_path.k") +api_instance = api.API() +result = api_instance.format_path(args) +print(result) +``` + +

+
+ +### lint_path + +Lint files and return error messages including errors and warnings. + +
Example +

+ +The content of `lint_path.k` is + +```python +import math + +a = 1 +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.LintPathArgs(paths=["lint_path.k"]) +api_instance = api.API() +result = api_instance.lint_path(args) +``` + +

+
+ +### validate_code + +Validate code using schema and JSON/YAML data strings. + +
Example +

+ +Python Code + +```python +import kcl_lib.api as api + +code = """\ +schema Person: + name: str + age: int + + check: + 0 < age < 120 +""" +data = '{"name": "Alice", "age": 10}' +args = api.ValidateCodeArgs(code=code, data=data, format="json") +api_instance = api.API() +result = api_instance.validate_code(args) +assert result.success == True +assert result.err_message == "" +``` + +

+
+ +### rename + +Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed. + +
Example +

+ +The content of `main.k` is + +```python +a = 1 +b = a +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.RenameArgs( + package_root=".", + symbol_path="a", + file_paths=["main.k"], + new_name="a2", +) +api_instance = api.API() +result = api_instance.rename(args) +``` + +

+
+ +### rename_code + +Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + +
Example +

+ +Python Code + +```python +import kcl_lib.api as api + +args = api.RenameCodeArgs( + package_root="/mock/path", + symbol_path="a", + source_codes={"/mock/path/main.k": "a = 1\nb = a"}, + new_name="a2", +) +api_instance = api.API() +result = api_instance.rename_code(args) +assert result.changed_codes["/mock/path/main.k"] == "a2 = 1\nb = a2" +``` + +

+
+ +### test + +Test KCL packages with test arguments. + +
Example +

+ +Python Code + +```python +import kcl_lib.api as api +args = api.TestArgs( + pkg_list=["path/to/testing/pkg/..."], +) +api_instance = api.API() +result = api_instance.test(args) +``` + +

+
+ +### load_settings_files + +Load the setting file config defined in `kcl.yaml` + +
Example +

+ +The content of `kcl.yaml` is + +```yaml +kcl_cli_configs: + strict_range_check: true +kcl_options: + - key: key + value: value +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.LoadSettingsFilesArgs( + work_dir=".", files=["kcl.yaml"] +) +api_instance = api.API() +result = api_instance.load_settings_files(args) +assert result.kcl_cli_configs.files == [] +assert result.kcl_cli_configs.strict_range_check == True +assert ( + result.kcl_options[0].key == "key" and result.kcl_options[0].value == '"value"' +) +``` + +

+
+ +### update_dependencies + +Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list. + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.UpdateDependenciesArgs( + manifest_path="module" +) +api_instance = api.API() +result = api_instance.update_dependencies(args) +pkg_names = [pkg.pkg_name for pkg in result.external_pkgs] +assert len(pkg_names) == 2 +assert "helloworld" in pkg_names +assert "flask" in pkg_names +``` + +

+
+ +Call `exec_program` with external dependencies + +
Example +

+ +The content of `module/kcl.mod` is + +```yaml +[package] +name = "mod_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" } +flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" } +``` + +The content of `module/main.k` is + +```python +import helloworld +import flask + +a = helloworld.The_first_kcl_program +``` + +Python Code + +```python +import kcl_lib.api as api + +args = api.UpdateDependenciesArgs( + manifest_path="module" +) +api_instance = api.API() +result = api_instance.update_dependencies(args) +exec_args = api.ExecProgramArgs( + k_filename_list=["module/main.k"], + external_pkgs=result.external_pkgs, +) +result = api_instance.exec_program(exec_args) +assert result.yaml_result == "a: Hello World!" +``` + +

+
+ +### get_version + +Return the KCL service version information. + +
Example +

+ +Python Code + +```python +import kcl_lib.api as api + +api_instance = api.API() +result = api_instance.get_version() +print(result.version_info) +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rest-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rest-api.md new file mode 100644 index 000000000..21ab13e1d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rest-api.md @@ -0,0 +1,1590 @@ +--- +sidebar_position: 2 +--- + +# Rest API + +## 1. Start REST Service + +The RestAPI service can be started in the following way: + +```shell +kcl server +``` + +The service can then be requested via the POST protocol: + +```shell +$ curl -X POST http://127.0.0.1:2021/api:protorpc/BuiltinService.Ping --data '{}' +{ + "error": "", + "result": {} +} +``` + +The POST request and the returned JSON data are consistent with the structure defined by Protobuf. + +## 2. `BuiltinService` + +Where the `/api:protorpc/BuiltinService.Ping` path represents the `Ping` method of the `BuiltinService` service. + +The complete `BuiltinService` is defined by Protobuf: + +```protobuf +service BuiltinService { + rpc Ping(PingArgs) returns(PingResult); + rpc ListMethod(ListMethodArgs) returns(ListMethodResult); +} + +message PingArgs { + string value = 1; +} +message PingResult { + string value = 1; +} + +message ListMethodArgs { + // empty +} +message ListMethodResult { + repeated string method_name_list = 1; +} +``` + +The `Ping` method can verify whether the service is normal, and the `ListMethod` method can query the list of all services and functions provided. + +## 3. `KclService` + +The `KclService` service is a service related to KCL functionality. The usage is the same as the `BuiltinService` service. + +For example, there is the following `Person` structure definition: + +```python +schema Person: + key: str + + check: + "value" in key # 'key' is required and 'key' must contain "value" +``` + +Then we want to use `Person` to verify the following JSON data: + +```json +{ "key": "value" } +``` + +This can be done through the `ValidateCode` method of the `KclService` service. Refer to the `ValidateCodeArgs` structure of the `ValidateCode` method: + +```protobuf +message ValidateCodeArgs { + string data = 1; + string code = 2; + string schema = 3; + string attribute_name = 4; + string format = 5; +} +``` + +Construct the JSON data required by the POST request according to the `ValidateCodeArgs` structure, which contains the `Person` definition and the JSON data to be verified: + +```json +{ + "code": "\nschema Person:\n key: str\n\n check:\n \"value\" in key # 'key' is required and 'key' must contain \"value\"\n", + "data": "{\"key\": \"value\"}" +} +``` + +Save this JSON data to the `vet-hello.json` file and verify it with the following command: + +```shell +$ curl -X POST \ + http://127.0.0.1:2021/api:protorpc/KclService.ValidateCode \ + -H "accept: application/json" \ + --data @./vet-hello.json +{ + "error": "", + "result": { + "success": true + } +} +``` + +## 4. Complete Protobuf Service Definition + +Cross-language APIs defined via Protobuf([https://github.com/kcl-lang/kcl/blob/main/kclvm/spec/gpyrpc/gpyrpc.proto](https://github.com/kcl-lang/kcl/blob/main/kclvm/spec/gpyrpc/gpyrpc.proto)): + +````protobuf +// Copyright The KCL Authors. All rights reserved. +// +// This file defines the request parameters and return structure of the KCL RPC server. + +syntax = "proto3"; + +package gpyrpc; + +// Message representing an external package for KCL. +// kcl main.k -E pkg_name=pkg_path +message ExternalPkg { + // Name of the package. + string pkg_name = 1; + // Path of the package. + string pkg_path = 2; +} + +// Message representing a key-value argument for KCL. +// kcl main.k -D name=value +message Argument { + // Name of the argument. + string name = 1; + // Value of the argument. + string value = 2; +} + +// ---------------------------------------------------------------------------- +// Error types +// ---------------------------------------------------------------------------- + +// Message representing an error. +message Error { + // Level of the error (e.g., "Error", "Warning"). + string level = 1; + // Error code. (e.g., "E1001") + string code = 2; + // List of error messages. + repeated Message messages = 3; +} + +// Message representing a detailed error message with a position. +message Message { + // The error message text. + string msg = 1; + // The position in the source code where the error occurred. + Position pos = 2; +} + +// ---------------------------------------------------------------------------- +// service request/response +// ---------------------------------------------------------------------------- + +// Service for built-in functionality. +service BuiltinService { + // Sends a ping request. + rpc Ping(PingArgs) returns (PingResult); + // Lists available methods. + rpc ListMethod(ListMethodArgs) returns (ListMethodResult); +} + +// Service for KCL VM interactions. +service KclService { + /// Ping KclService, return the same value as the parameter + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "Ping", + /// "params": { + /// "value": "hello" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "value": "hello" + /// }, + /// "id": 1 + /// } + /// ``` + rpc Ping(PingArgs) returns (PingResult); + + /// GetVersion KclService, return the kclvm service version information + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "GetVersion", + /// "params": {}, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "version": "0.9.1", + /// "checksum": "c020ab3eb4b9179219d6837a57f5d323", + /// "git_sha": "1a9a72942fffc9f62cb8f1ae4e1d5ca32aa1f399", + /// "version_info": "Version: 0.9.1-c020ab3eb4b9179219d6837a57f5d323\nPlatform: aarch64-apple-darwin\nGitCommit: 1a9a72942fffc9f62cb8f1ae4e1d5ca32aa1f399" + /// }, + /// "id": 1 + /// } + /// ``` + rpc GetVersion(GetVersionArgs) returns (GetVersionResult); + + /// Parse KCL program with entry files. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ParseProgram", + /// "params": { + /// "paths": ["./src/testdata/test.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "ast_json": "{...}", + /// "paths": ["./src/testdata/test.k"], + /// "errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ParseProgram(ParseProgramArgs) returns (ParseProgramResult); + + /// Parse KCL single file to Module AST JSON string with import dependencies + /// and parse errors. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ParseFile", + /// "params": { + /// "path": "./src/testdata/parse/main.k" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "ast_json": "{...}", + /// "deps": ["./dep1", "./dep2"], + /// "errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ParseFile(ParseFileArgs) returns (ParseFileResult); + + /// load_package provides users with the ability to parse kcl program and semantic model + /// information including symbols, types, definitions, etc. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "LoadPackage", + /// "params": { + /// "parse_args": { + /// "paths": ["./src/testdata/parse/main.k"] + /// }, + /// "resolve_ast": true + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "program": "{...}", + /// "paths": ["./src/testdata/parse/main.k"], + /// "parse_errors": [], + /// "type_errors": [], + /// "symbols": { ... }, + /// "scopes": { ... }, + /// "node_symbol_map": { ... }, + /// "symbol_node_map": { ... }, + /// "fully_qualified_name_map": { ... }, + /// "pkg_scope_map": { ... } + /// }, + /// "id": 1 + /// } + /// ``` + rpc LoadPackage(LoadPackageArgs) returns (LoadPackageResult); + + /// list_options provides users with the ability to parse kcl program and get all option information. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ListOptions", + /// "params": { + /// "paths": ["./src/testdata/option/main.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "options": [ + /// { "name": "option1", "type": "str", "required": true, "default_value": "", "help": "option 1 help" }, + /// { "name": "option2", "type": "int", "required": false, "default_value": "0", "help": "option 2 help" }, + /// { "name": "option3", "type": "bool", "required": false, "default_value": "false", "help": "option 3 help" } + /// ] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ListOptions(ParseProgramArgs) returns (ListOptionsResult); + + /// list_variables provides users with the ability to parse kcl program and get all variables by specs. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ListVariables", + /// "params": { + /// "files": ["./src/testdata/variables/main.k"], + /// "specs": ["a"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "variables": { + /// "a": { + /// "variables": [ + /// { "value": "1", "type_name": "int", "op_sym": "", "list_items": [], "dict_entries": [] } + /// ] + /// } + /// }, + /// "unsupported_codes": [], + /// "parse_errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc ListVariables(ListVariablesArgs) returns (ListVariablesResult); + + /// Execute KCL file with args. **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["test.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "json_result": "{\"alice\": {\"age\": 18}}", + /// "yaml_result": "alice:\n age: 18", + /// "log_message": "", + /// "err_message": "" + /// }, + /// "id": 1 + /// } + /// + /// // Request with code + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "k_filename_list": ["file.k"], + /// "k_code_list": ["alice = {age = 18}"] + /// }, + /// "id": 2 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "json_result": "{\"alice\": {\"age\": 18}}", + /// "yaml_result": "alice:\n age: 18", + /// "log_message": "", + /// "err_message": "" + /// }, + /// "id": 2 + /// } + /// + /// // Error case - cannot find file + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "k_filename_list": ["invalid_file.k"] + /// }, + /// "id": 3 + /// } + /// + /// // Error Response + /// { + /// "jsonrpc": "2.0", + /// "error": { + /// "code": -32602, + /// "message": "Cannot find the kcl file" + /// }, + /// "id": 3 + /// } + /// + /// // Error case - no input files + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecProgram", + /// "params": { + /// "k_filename_list": [] + /// }, + /// "id": 4 + /// } + /// + /// // Error Response + /// { + /// "jsonrpc": "2.0", + /// "error": { + /// "code": -32602, + /// "message": "No input KCL files or paths" + /// }, + /// "id": 4 + /// } + /// ``` + rpc ExecProgram(ExecProgramArgs) returns (ExecProgramResult); + + /// Build the KCL program to an artifact. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "BuildProgram", + /// "params": { + /// "exec_args": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["test.k"] + /// }, + /// "output": "./build" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "path": "./build/test.k" + /// }, + /// "id": 1 + /// } + /// ``` + rpc BuildProgram(BuildProgramArgs) returns (BuildProgramResult); + + /// Execute the KCL artifact with args. **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ExecArtifact", + /// "params": { + /// "path": "./artifact_path", + /// "exec_args": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["test.k"] + /// } + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "json_result": "{\"alice\": {\"age\": 18}}", + /// "yaml_result": "alice:\n age: 18", + /// "log_message": "", + /// "err_message": "" + /// }, + /// "id": 1 + /// } + /// ``` + rpc ExecArtifact(ExecArtifactArgs) returns (ExecProgramResult); + + /// Override KCL file with args. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "OverrideFile", + /// "params": { + /// "file": "./src/testdata/test.k", + /// "specs": ["alice.age=18"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "result": true, + /// "parse_errors": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc OverrideFile(OverrideFileArgs) returns (OverrideFileResult); + + /// Get schema type mapping. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "GetSchemaTypeMapping", + /// "params": { + /// "exec_args": { + /// "work_dir": "./src/testdata", + /// "k_filename_list": ["main.k"], + /// "external_pkgs": [ + /// { + /// "pkg_name":"pkg", + /// "pkg_path": "./src/testdata/pkg" + /// } + /// ] + /// }, + /// "schema_name": "Person" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "schema_type_mapping": { + /// "Person": { + /// "type": "schema", + /// "schema_name": "Person", + /// "properties": { + /// "name": { "type": "str" }, + /// "age": { "type": "int" } + /// }, + /// "required": ["name", "age"], + /// "decorators": [] + /// } + /// } + /// }, + /// "id": 1 + /// } + /// ``` + rpc GetSchemaTypeMapping(GetSchemaTypeMappingArgs) returns (GetSchemaTypeMappingResult); + + /// Format code source. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "FormatCode", + /// "params": { + /// "source": "schema Person {\n name: str\n age: int\n}\nperson = Person {\n name = \"Alice\"\n age = 18\n}\n" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "formatted": "schema Person {\n name: str\n age: int\n}\nperson = Person {\n name = \"Alice\"\n age = 18\n}\n" + /// }, + /// "id": 1 + /// } + /// ``` + rpc FormatCode(FormatCodeArgs) returns (FormatCodeResult); + + /// Format KCL file or directory path contains KCL files and returns the changed file paths. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "FormatPath", + /// "params": { + /// "path": "./src/testdata/test.k" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "changed_paths": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc FormatPath(FormatPathArgs) returns (FormatPathResult); + + /// Lint files and return error messages including errors and warnings. + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "LintPath", + /// "params": { + /// "paths": ["./src/testdata/test-lint.k"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "results": ["Module 'math' imported but unused"] + /// }, + /// "id": 1 + /// } + /// ``` + rpc LintPath(LintPathArgs) returns (LintPathResult); + + /// Validate code using schema and data strings. + /// + /// **Note that it is not thread safe.** + /// + /// # Examples + /// + /// ```jsonrpc + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "ValidateCode", + /// "params": { + /// "code": "schema Person {\n name: str\n age: int\n check: 0 < age < 120\n}", + /// "data": "{\"name\": \"Alice\", \"age\": 10}" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "success": true, + /// "err_message": "" + /// }, + /// "id": 1 + /// } + /// ``` + rpc ValidateCode(ValidateCodeArgs) returns (ValidateCodeResult); + + rpc ListDepFiles(ListDepFilesArgs) returns (ListDepFilesResult); + /// Build setting file config from args. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "LoadSettingsFiles", + /// "params": { + /// "work_dir": "./src/testdata/settings", + /// "files": ["./src/testdata/settings/kcl.yaml"] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "kcl_cli_configs": { + /// "files": ["./src/testdata/settings/kcl.yaml"], + /// "output": "", + /// "overrides": [], + /// "path_selector": [], + /// "strict_range_check": false, + /// "disable_none": false, + /// "verbose": 0, + /// "debug": false, + /// "sort_keys": false, + /// "show_hidden": false, + /// "include_schema_type_path": false, + /// "fast_eval": false + /// }, + /// "kcl_options": [] + /// }, + /// "id": 1 + /// } + /// ``` + rpc LoadSettingsFiles(LoadSettingsFilesArgs) returns (LoadSettingsFilesResult); + + /// Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. + /// Return the file paths that got changed. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "Rename", + /// "params": { + /// "package_root": "./src/testdata/rename_doc", + /// "symbol_path": "a", + /// "file_paths": ["./src/testdata/rename_doc/main.k"], + /// "new_name": "a2" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "changed_files": ["./src/testdata/rename_doc/main.k"] + /// }, + /// "id": 1 + /// } + /// ``` + rpc Rename(RenameArgs) returns (RenameResult); + + /// Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "RenameCode", + /// "params": { + /// "package_root": "/mock/path", + /// "symbol_path": "a", + /// "source_codes": { + /// "/mock/path/main.k": "a = 1\nb = a" + /// }, + /// "new_name": "a2" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "changed_codes": { + /// "/mock/path/main.k": "a2 = 1\nb = a2" + /// } + /// }, + /// "id": 1 + /// } + /// ``` + rpc RenameCode(RenameCodeArgs) returns (RenameCodeResult); + + /// Test KCL packages with test arguments. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "Test", + /// "params": { + /// "pkg_list": ["./src/testdata/testing/module/..."] + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "info": [ + /// {"name": "test_case_1", "error": "", "duration": 1000, "log_message": ""}, + /// {"name": "test_case_2", "error": "some error", "duration": 2000, "log_message": ""} + /// ] + /// }, + /// "id": 1 + /// } + /// ``` + rpc Test(TestArgs) returns (TestResult); + + /// Download and update dependencies defined in the kcl.mod file. + /// + /// # Examples + /// + /// + /// // Request + /// { + /// "jsonrpc": "2.0", + /// "method": "UpdateDependencies", + /// "params": { + /// "manifest_path": "./src/testdata/update_dependencies" + /// }, + /// "id": 1 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "external_pkgs": [ + /// {"pkg_name": "pkg1", "pkg_path": "./src/testdata/update_dependencies/pkg1"} + /// ] + /// }, + /// "id": 1 + /// } + /// + /// // Request with vendor flag + /// { + /// "jsonrpc": "2.0", + /// "method": "UpdateDependencies", + /// "params": { + /// "manifest_path": "./src/testdata/update_dependencies", + /// "vendor": true + /// }, + /// "id": 2 + /// } + /// + /// // Response + /// { + /// "jsonrpc": "2.0", + /// "result": { + /// "external_pkgs": [ + /// {"pkg_name": "pkg1", "pkg_path": "./src/testdata/update_dependencies/pkg1"} + /// ] + /// }, + /// "id": 2 + /// } + /// ``` + rpc UpdateDependencies(UpdateDependenciesArgs) returns (UpdateDependenciesResult); +} + +// Message for ping request arguments. +message PingArgs { + // Value to be sent in the ping request. + string value = 1; +} + +// Message for ping response. +message PingResult { + // Value received in the ping response. + string value = 1; +} + +// Message for version request arguments. Empty message. +message GetVersionArgs { + // empty +} + +// Message for version response. +message GetVersionResult { + // KCL version. + string version = 1; + // Checksum of the KCL version. + string checksum = 2; + // Git Git SHA of the KCL code repo. + string git_sha = 3; + // Detailed version information as a string. + string version_info = 4; +} + +// Message for list method request arguments. Empty message. +message ListMethodArgs { + // empty +} + +// Message for list method response. +message ListMethodResult { + // List of available method names. + repeated string method_name_list = 1; +} + +// Message for parse file request arguments. +message ParseFileArgs { + // Path of the file to be parsed. + string path = 1; + // Source code to be parsed. + string source = 2; + // External packages path. + repeated ExternalPkg external_pkgs = 3; +} + +// Message for parse file response. +message ParseFileResult { + // Abstract Syntax Tree (AST) in JSON format. + string ast_json = 1; + // File dependency paths. + repeated string deps = 2; + // List of parse errors. + repeated Error errors = 3; +} + +// Message for parse program request arguments. +message ParseProgramArgs { + // Paths of the program files to be parsed. + repeated string paths = 1; + // Source codes to be parsed. + repeated string sources = 2; + // External packages path. + repeated ExternalPkg external_pkgs = 3; +} + +// Message for parse program response. +message ParseProgramResult { + // Abstract Syntax Tree (AST) in JSON format. + string ast_json = 1; + // Returns the files in the order they should be compiled. + repeated string paths = 2; + // List of parse errors. + repeated Error errors = 3; +} + +// Message for load package request arguments. +message LoadPackageArgs { + // Arguments for parsing the program. + ParseProgramArgs parse_args = 1; + // Flag indicating whether to resolve AST. + bool resolve_ast = 2; + // Flag indicating whether to load built-in modules. + bool load_builtin = 3; + // Flag indicating whether to include AST index. + bool with_ast_index = 4; +} + +// Message for load package response. +message LoadPackageResult { + // Program Abstract Syntax Tree (AST) in JSON format. + string program = 1; + // Returns the files in the order they should be compiled. + repeated string paths = 2; + // List of parse errors. + repeated Error parse_errors = 3; + // List of type errors. + repeated Error type_errors = 4; + // Map of scopes with scope index as key. + map scopes = 5; + // Map of symbols with symbol index as key. + map symbols = 6; + // Map of node-symbol associations with AST index UUID as key. + map node_symbol_map = 7; + // Map of symbol-node associations with symbol index as key. + map symbol_node_map = 8; + // Map of fully qualified names with symbol index as key. + map fully_qualified_name_map = 9; + // Map of package scope with package path as key. + map pkg_scope_map = 10; +} + +// Message for list options response. +message ListOptionsResult { + // List of available options. + repeated OptionHelp options = 2; +} + +// Message representing a help option. +message OptionHelp { + // Name of the option. + string name = 1; + // Type of the option. + string type = 2; + // Flag indicating if the option is required. + bool required = 3; + // Default value of the option. + string default_value = 4; + // Help text for the option. + string help = 5; +} + +// Message representing a symbol in KCL. +message Symbol { + // Type of the symbol. + KclType ty = 1; + // Name of the symbol. + string name = 2; + // Owner of the symbol. + SymbolIndex owner = 3; + // Definition of the symbol. + SymbolIndex def = 4; + // Attributes of the symbol. + repeated SymbolIndex attrs = 5; + // Flag indicating if the symbol is global. + bool is_global = 6; +} + +// Message representing a scope in KCL. +message Scope { + // Type of the scope. + string kind = 1; + // Parent scope. + ScopeIndex parent = 2; + // Owner of the scope. + SymbolIndex owner = 3; + // Children of the scope. + repeated ScopeIndex children = 4; + // Definitions in the scope. + repeated SymbolIndex defs = 5; +} + +// Message representing a symbol index. +message SymbolIndex { + // Index identifier. + uint64 i = 1; + // Global identifier. + uint64 g = 2; + // Type of the symbol or scope. + string kind = 3; +} + +// Message representing a scope index. +message ScopeIndex { + // Index identifier. + uint64 i = 1; + // Global identifier. + uint64 g = 2; + // Type of the scope. + string kind = 3; +} + +// Message for execute program request arguments. +message ExecProgramArgs { + // Working directory. + string work_dir = 1; + // List of KCL filenames. + repeated string k_filename_list = 2; + // List of KCL codes. + repeated string k_code_list = 3; + // Arguments for the program. + repeated Argument args = 4; + // Override configurations. + repeated string overrides = 5; + // Flag to disable YAML result. + bool disable_yaml_result = 6; + // Flag to print override AST. + bool print_override_ast = 7; + // Flag for strict range check. + bool strict_range_check = 8; + // Flag to disable none values. + bool disable_none = 9; + // Verbose level. + int32 verbose = 10; + // Debug level. + int32 debug = 11; + // Flag to sort keys in YAML/JSON results. + bool sort_keys = 12; + // External packages path. + repeated ExternalPkg external_pkgs = 13; + // Flag to include schema type path in results. + bool include_schema_type_path = 14; + // Flag to compile only without execution. + bool compile_only = 15; + // Flag to show hidden attributes. + bool show_hidden = 16; + // Path selectors for results. + repeated string path_selector = 17; + // Flag for fast evaluation. + bool fast_eval = 18; +} + +// Message for execute program response. +message ExecProgramResult { + // Result in JSON format. + string json_result = 1; + // Result in YAML format. + string yaml_result = 2; + // Log message from execution. + string log_message = 3; + // Error message from execution. + string err_message = 4; +} + +// Message for build program request arguments. +message BuildProgramArgs { + // Arguments for executing the program. + ExecProgramArgs exec_args = 1; + // Output path. + string output = 2; +} + +// Message for build program response. +message BuildProgramResult { + // Path of the built program. + string path = 1; +} + +// Message for execute artifact request arguments. +message ExecArtifactArgs { + // Path of the artifact. + string path = 1; + // Arguments for executing the program. + ExecProgramArgs exec_args = 2; +} + +// Message for reset plugin request arguments. +message ResetPluginArgs { + // Root path for the plugin. + string plugin_root = 1; +} + +// Message for reset plugin response. Empty message. +message ResetPluginResult { + // empty +} + +// Message for format code request arguments. +message FormatCodeArgs { + // Source code to be formatted. + string source = 1; +} + +// Message for format code response. +message FormatCodeResult { + // Formatted code as bytes. + bytes formatted = 1; +} + +// Message for format file path request arguments. +message FormatPathArgs { + // Path of the file to format. + string path = 1; +} + +// Message for format file path response. +message FormatPathResult { + // List of changed file paths. + repeated string changed_paths = 1; +} + +// Message for lint file path request arguments. +message LintPathArgs { + // Paths of the files to lint. + repeated string paths = 1; +} + +// Message for lint file path response. +message LintPathResult { + // List of lint results. + repeated string results = 1; +} + +// Message for override file request arguments. +message OverrideFileArgs { + // Path of the file to override. + string file = 1; + // List of override specifications. + repeated string specs = 2; + // List of import paths. + repeated string import_paths = 3; +} + +// Message for override file response. +message OverrideFileResult { + // Result of the override operation. + bool result = 1; + // List of parse errors encountered. + repeated Error parse_errors = 2; +} + +// Message for list variables options. +message ListVariables_Options { + // Flag to merge program configuration. + bool merge_program = 1; +} + +// Message representing a list of variables. +message VariableList { + // List of variables. + repeated Variable variables = 1; +} + +// Message for list variables request arguments. +message ListVariablesArgs { + // Files to be processed. + repeated string files = 1; + // Specifications for variables. + repeated string specs = 2; + // Options for listing variables. + ListVariables_Options options = 3; +} + +// Message for list variables response. +message ListVariablesResult { + // Map of variable lists by file. + map variables = 1; + // List of unsupported codes. + repeated string unsupported_codes = 2; + // List of parse errors encountered. + repeated Error parse_errors = 3; +} + +// Message representing a variable. +message Variable { + // Value of the variable. + string value = 1; + // Type name of the variable. + string type_name = 2; + // Operation symbol associated with the variable. + string op_sym = 3; + // List items if the variable is a list. + repeated Variable list_items = 4; + // Dictionary entries if the variable is a dictionary. + repeated MapEntry dict_entries = 5; +} + +// Message representing a map entry. +message MapEntry { + // Key of the map entry. + string key = 1; + // Value of the map entry. + Variable value = 2; +} + +// Message for get schema type mapping request arguments. +message GetSchemaTypeMappingArgs { + // Arguments for executing the program. + ExecProgramArgs exec_args = 1; + // Name of the schema. + string schema_name = 2; +} + +// Message for get schema type mapping response. +message GetSchemaTypeMappingResult { + // Map of schema type mappings. + map schema_type_mapping = 1; +} + +// Message for validate code request arguments. +message ValidateCodeArgs { + // Path to the data file. + string datafile = 1; + // Data content. + string data = 2; + // Path to the code file. + string file = 3; + // Source code content. + string code = 4; + // Name of the schema. + string schema = 5; + // Name of the attribute. + string attribute_name = 6; + // Format of the validation (e.g., "json", "yaml"). + string format = 7; +} + +// Message for validate code response. +message ValidateCodeResult { + // Flag indicating if validation was successful. + bool success = 1; + // Error message from validation. + string err_message = 2; +} + +// Message representing a position in the source code. +message Position { + // Line number. + int64 line = 1; + // Column number. + int64 column = 2; + // Filename the position refers to. + string filename = 3; +} + +// Message for list dependency files request arguments. +message ListDepFilesArgs { + // Working directory. + string work_dir = 1; + // Flag to use absolute paths. + bool use_abs_path = 2; + // Flag to include all files. + bool include_all = 3; + // Flag to use fast parser. + bool use_fast_parser = 4; +} + +// Message for list dependency files response. +message ListDepFilesResult { + // Root package path. + string pkgroot = 1; + // Package path. + string pkgpath = 2; + // List of file paths in the package. + repeated string files = 3; +} + +// --------------------------------------------------------------------------------- +// LoadSettingsFiles API +// Input work dir and setting files and return the merged kcl singleton config. +// --------------------------------------------------------------------------------- + +// Message for load settings files request arguments. +message LoadSettingsFilesArgs { + // Working directory. + string work_dir = 1; + // Setting files to load. + repeated string files = 2; +} + +// Message for load settings files response. +message LoadSettingsFilesResult { + // KCL CLI configuration. + CliConfig kcl_cli_configs = 1; + // List of KCL options as key-value pairs. + repeated KeyValuePair kcl_options = 2; +} + +// Message representing KCL CLI configuration. +message CliConfig { + // List of files. + repeated string files = 1; + // Output path. + string output = 2; + // List of overrides. + repeated string overrides = 3; + // Path selectors. + repeated string path_selector = 4; + // Flag for strict range check. + bool strict_range_check = 5; + // Flag to disable none values. + bool disable_none = 6; + // Verbose level. + int64 verbose = 7; + // Debug flag. + bool debug = 8; + // Flag to sort keys in YAML/JSON results. + bool sort_keys = 9; + // Flag to show hidden attributes. + bool show_hidden = 10; + // Flag to include schema type path in results. + bool include_schema_type_path = 11; + // Flag for fast evaluation. + bool fast_eval = 12; +} + +// Message representing a key-value pair. +message KeyValuePair { + // Key of the pair. + string key = 1; + // Value of the pair. + string value = 2; +} + +// --------------------------------------------------------------------------------- +// Rename API +// Find all the occurrences of the target symbol and rename them. +// This API will rewrite files if they contain symbols to be renamed. +// --------------------------------------------------------------------------------- + +// Message for rename request arguments. +message RenameArgs { + // File path to the package root. + string package_root = 1; + // Path to the target symbol to be renamed. + string symbol_path = 2; + // Paths to the source code files. + repeated string file_paths = 3; + // New name of the symbol. + string new_name = 4; +} + +// Message for rename response. +message RenameResult { + // List of file paths that got changed. + repeated string changed_files = 1; +} + +// --------------------------------------------------------------------------------- +// RenameCode API +// Find all the occurrences of the target symbol and rename them. +// This API won't rewrite files but return the modified code if any code has been changed. +// --------------------------------------------------------------------------------- + +// Message for rename code request arguments. +message RenameCodeArgs { + // File path to the package root. + string package_root = 1; + // Path to the target symbol to be renamed. + string symbol_path = 2; + // Map of source code with filename as key and code as value. + map source_codes = 3; + // New name of the symbol. + string new_name = 4; +} + +// Message for rename code response. +message RenameCodeResult { + // Map of changed code with filename as key and modified code as value. + map changed_codes = 1; +} + +// --------------------------------------------------------------------------------- +// Test API +// Test KCL packages with test arguments. +// --------------------------------------------------------------------------------- + +// Message for test request arguments. +message TestArgs { + // Execution program arguments. + ExecProgramArgs exec_args = 1; + // List of KCL package paths to be tested. + repeated string pkg_list = 2; + // Regular expression for filtering tests to run. + string run_regexp = 3; + // Flag to stop the test run on the first failure. + bool fail_fast = 4; +} + +// Message for test response. +message TestResult { + // List of test case information. + repeated TestCaseInfo info = 2; +} + +// Message representing information about a single test case. +message TestCaseInfo { + // Name of the test case. + string name = 1; + // Error message if any. + string error = 2; + // Duration of the test case in microseconds. + uint64 duration = 3; + // Log message from the test case. + string log_message = 4; +} + +// --------------------------------------------------------------------------------- +// UpdateDependencies API +// Download and update dependencies defined in the kcl.mod file. +// --------------------------------------------------------------------------------- + +// Message for update dependencies request arguments. +message UpdateDependenciesArgs { + // Path to the manifest file. + string manifest_path = 1; + // Flag to vendor dependencies locally. + bool vendor = 2; +} + +// Message for update dependencies response. +message UpdateDependenciesResult { + // List of external packages updated. + repeated ExternalPkg external_pkgs = 3; +} + +// ---------------------------------------------------------------------------- +// KCL Type Structure +// ---------------------------------------------------------------------------- + +// Message representing a KCL type. +message KclType { + // Type name (e.g., schema, dict, list, str, int, float, bool, any, union, number_multiplier). + string type = 1; + // Union types if applicable. + repeated KclType union_types = 2; + // Default value of the type. + string default = 3; + // Name of the schema if applicable. + string schema_name = 4; + // Documentation for the schema. + string schema_doc = 5; + // Properties of the schema as a map with property name as key. + map properties = 6; + // List of required schema properties. + repeated string required = 7; + // Key type if the KclType is a dictionary. + KclType key = 8; + // Item type if the KclType is a list or dictionary. + KclType item = 9; + // Line number where the type is defined. + int32 line = 10; + // List of decorators for the schema. + repeated Decorator decorators = 11; + // Absolute path of the file where the attribute is located. + string filename = 12; + // Path of the package where the attribute is located. + string pkg_path = 13; + // Documentation for the attribute. + string description = 14; + // Map of examples with example name as key. + map examples = 15; + // Base schema if applicable. + KclType base_schema = 16; +} + +// Message representing a decorator in KCL. +message Decorator { + // Name of the decorator. + string name = 1; + // Arguments for the decorator. + repeated string arguments = 2; + // Keyword arguments for the decorator as a map with keyword name as key. + map keywords = 3; +} + +// Message representing an example in KCL. +message Example { + // Short description for the example. + string summary = 1; + // Long description for the example. + string description = 2; + // Embedded literal example. + string value = 3; +} + +// ---------------------------------------------------------------------------- +// END +// ---------------------------------------------------------------------------- +```` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rust-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rust-api.md new file mode 100644 index 000000000..6c24302bb --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/rust-api.md @@ -0,0 +1,320 @@ +--- +sidebar_position: 7 +--- + +# Rust API + +## Installation + +```shell +cargo add --git https://github.com/kcl-lang/lib +``` + +## Quick Start + +```rust +use kcl_lang::*; +use anyhow::Result; + +fn main() -> Result<()> { + let api = API::default(); + let args = &ExecProgramArgs { + k_filename_list: vec!["main.k".to_string()], + k_code_list: vec!["a = 1".to_string()], + ..Default::default() + }; + let exec_result = api.exec_program(args)?; + println!("{}", exec_result.yaml_result); + Ok(()) +} +``` + +More Rust APIs can be found [here](https://github.com/kcl-lang/kcl). If you want to use the sub crate of KCL Rust core, you can run the following command. + +```shell +# Take the kclvm-runtime as an example. +cargo add --git https://github.com/kcl-lang/kcl kclvm-runtime +``` + +## API Reference + +### exec_program + +Execute KCL file with args. + +
Example +

+ +```rust +use kcl_lang::*; +use std::path::Path; +// File case +let serv = API::default(); +let args = &ExecProgramArgs { + work_dir: Path::new(".").join("src").join("testdata").canonicalize().unwrap().display().to_string(), + k_filename_list: vec!["test.k".to_string()], + ..Default::default() +}; +let exec_result = serv.exec_program(args).unwrap(); +assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); + +// Code case +let args = &ExecProgramArgs { + k_filename_list: vec!["file.k".to_string()], + k_code_list: vec!["alice = {age = 18}".to_string()], + ..Default::default() +}; +let exec_result = serv.exec_program(args).unwrap(); +assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); + +// Error case +let args = &ExecProgramArgs { + k_filename_list: vec!["invalid_file.k".to_string()], + ..Default::default() +}; +let error = serv.exec_program(args).unwrap_err(); +assert!(error.to_string().contains("Cannot find the kcl file"), "{error}"); + +let args = &ExecProgramArgs { + k_filename_list: vec![], + ..Default::default() +}; +let error = serv.exec_program(args).unwrap_err(); +assert!(error.to_string().contains("No input KCL files or paths"), "{error}"); +``` + +

+
+ +### format_code + +Service for formatting a code source and returns the formatted source and whether the source is changed. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let source = r#"schema Person: + name: str + age: int + +person = Person { + name = "Alice" + age = 18 +} + +"#.to_string(); +let result = serv.format_code(&FormatCodeArgs { + source: source.clone(), + ..Default::default() +}).unwrap(); +assert_eq!(result.formatted, source.as_bytes().to_vec()); +``` + +

+
+ +### format_path + +Service for formatting kcl file or directory path contains kcl files and returns the changed file paths. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let result = serv.format_path(&FormatPathArgs { + path: "./src/testdata/test.k".to_string(), + ..Default::default() +}).unwrap(); +assert!(result.changed_paths.is_empty()); +``` + +

+
+ +### lint_path + +Service for KCL Lint API, check a set of files, skips execute, returns error message including errors and warnings. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let result = serv.lint_path(&LintPathArgs { + paths: vec!["./src/testdata/test-lint.k".to_string()], + ..Default::default() +}).unwrap(); +assert_eq!(result.results, vec!["Module 'math' imported but unused".to_string()]); +``` + +

+
+ +### validate_code + +Service for validating the data string using the schema code string, when the parameter schema is omitted, use the first schema appeared in the kcl code. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let code = r#" +schema Person: + name: str + age: int + + check: + 0 < age < 120 +"#.to_string(); +let data = r#" +{ + "name": "Alice", + "age": 10 +} +"#.to_string(); +let result = serv.validate_code(&ValidateCodeArgs { + code, + data, + ..Default::default() +}).unwrap(); +assert_eq!(result.success, true); +``` + +

+
+ +### load_settings_files + +Service for building setting file config from args. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let result = serv.load_settings_files(&LoadSettingsFilesArgs { + files: vec!["./src/testdata/settings/kcl.yaml".to_string()], + work_dir: "./src/testdata/settings".to_string(), + ..Default::default() +}).unwrap(); +assert_eq!(result.kcl_options.len(), 1); +``` + +

+
+ +### rename + +Service for renaming all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. return the file paths got changed. + +
Example +

+ +```rust +use kcl_lang::*; + +let result = serv.rename(&RenameArgs { + package_root: "./src/testdata/rename_doc".to_string(), + symbol_path: "a".to_string(), + file_paths: vec!["./src/testdata/rename_doc/main.k".to_string()], + new_name: "a2".to_string(), +}).unwrap(); +assert_eq!(result.changed_files.len(), 1); +``` + +

+
+ +### rename_code + +Service for renaming all the occurrences of the target symbol and rename them. This API won’t rewrite files but return the modified code if any code has been changed. return the changed code. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let result = serv.rename_code(&RenameCodeArgs { + package_root: "/mock/path".to_string(), + symbol_path: "a".to_string(), + source_codes: vec![("/mock/path/main.k".to_string(), "a = 1\nb = a".to_string())].into_iter().collect(), + new_name: "a2".to_string(), +}).unwrap(); +assert_eq!(result.changed_codes.len(), 1); +assert_eq!(result.changed_codes.get("/mock/path/main.k").unwrap(), "a2 = 1\nb = a2"); +``` + +

+
+ +### test + +Service for the testing tool. + +
Example +

+ +```rust +use kcl_lang::*; + +let serv = API::default(); +let result = serv.test(&TestArgs { + pkg_list: vec!["./src/testdata/testing/module/...".to_string()], + ..TestArgs::default() +}).unwrap(); +assert_eq!(result.info.len(), 2); +// Passed case +assert!(result.info[0].error.is_empty()); +// Failed case +assert!(result.info[1].error.is_empty()); +``` + +

+
+ +### update_dependencies + +update_dependencies provides users with the ability to update kcl module dependencies. + +
Example +

+ +```rust +use kcl_lang::*; +use std::path::Path; +use std::fs::remove_dir_all; + +let serv = API::default(); +let result = serv.update_dependencies(&UpdateDependenciesArgs { + manifest_path: "./src/testdata/update_dependencies".to_string(), + ..Default::default() +}).unwrap(); +assert_eq!(result.external_pkgs.len(), 1); + +let result = serv.update_dependencies(&UpdateDependenciesArgs { + manifest_path: "./src/testdata/update_dependencies".to_string(), + vendor: true, +}).unwrap(); +assert_eq!(result.external_pkgs.len(), 1); +let vendor_path = Path::new("./src/testdata/update_dependencies/vendor"); +remove_dir_all(vendor_path); +``` + +

+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/swift-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/swift-api.md new file mode 100644 index 000000000..3720809e3 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/swift-api.md @@ -0,0 +1,18 @@ +--- +sidebar_position: 9 +--- + +# Swift API + +The official [Swift KCL package](https://github.com/kcl-lang/lib/tree/main/swift) has not been released yet. Issues and PRs are welcome! + +## Quick Start + +```swift +import KclLib + +let api = API() +var execArgs = ExecProgramArgs() +execArgs.kFilenameList.append("schema.k") +let result = try api.execProgram(execArgs) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/wasm-api.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/wasm-api.md new file mode 100644 index 000000000..c7e8682e6 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/reference/xlang-api/wasm-api.md @@ -0,0 +1,248 @@ +--- +sidebar_position: 13 +--- + +# WASM API + +The KCL core is written by Rust and can be compiled to the `wasm-wasi` target using toolchains such as cargo. With the help of WASM, we can also easily achieve multilingual and browser integration. Here is how we can use the KCL WASM module in Browser, Node.js, Go and Rust. + +## Quick Start + +We can find and download KCL WASM module from [here](https://github.com/kcl-lang/lib/tree/main/wasm) + +## Browser + +Install the dependency + +```shell +npm install buffer @wasmer/wasi @kcl-lang/wasm-lib +``` + +> **NOTE:** +> Buffer is required by @wasmer/wasi. + +Write the code + +```typescript +import { load, invokeKCLRun } from "@kcl-lang/wasm-lib"; + +async function main() { + const inst = await load(); + const result = invokeKCLRun(inst, { + filename: "test.k", + source: ` +schema Person: + name: str + +p = Person {name = "Alice"}`, + }); + console.log(result); +} + +main(); +``` + +Here, we use `webpack` to bundle the website, the `webpack.config.js` config as follows. + +> **NOTE:**: +> This configuration includes necessary settings for @wasmer/wasi and other required plugins. + +```js +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const path = require("path"); +const webpack = require("webpack"); + +const dist = path.resolve("./dist"); +const isProduction = process.argv.some((x) => x === "--mode=production"); +const hash = isProduction ? ".[contenthash]" : ""; + +module.exports = { + mode: "development", + entry: { + main: "./src/main.ts", + }, + target: "web", + output: { + path: dist, + filename: `[name]${hash}.js`, + clean: true, + }, + devServer: { + hot: true, + port: 9000, + }, + module: { + rules: [ + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, "css-loader"], + }, + { + test: /\.m?js$/, + resourceQuery: { not: [/(raw|wasm)/] }, + }, + { + resourceQuery: /raw/, + type: "asset/source", + }, + { + resourceQuery: /wasm/, + type: "asset/resource", + generator: { + filename: "wasm/[name][ext]", + }, + }, + ], + }, + plugins: [ + new MiniCssExtractPlugin(), + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "./src/index.html"), + }), + new webpack.IgnorePlugin({ + resourceRegExp: /^(path|ws|crypto|fs|os|util|node-fetch)$/, + }), + // needed by @wasmer/wasi + new webpack.ProvidePlugin({ + Buffer: ["buffer", "Buffer"], + }), + ], + externals: { + // needed by @wasmer/wasi + "wasmer_wasi_js_bg.wasm": true, + }, + resolve: { + fallback: { + // needed by @wasmer/wasi + buffer: require.resolve("buffer/"), + }, + }, +}; +``` + +For a complete working example, refer to [here](https://github.com/kcl-lang/lib/tree/main/wasm/examples/browser). + +### Troubleshooting + +If you encounter any issues, make sure: + +- All dependencies are correctly installed. +- Your `webpack.config.js` is properly set up. +- You're using a modern browser that supports WebAssembly. +- The KCL WASM module is correctly loaded and accessible. + +## Node.js + +Install the dependency + +```shell +npm install @kcl-lang/wasm-lib +``` + +Write the code + +```typescript +import { load, invokeKCLRun } from "@kcl-lang/wasm-lib"; + +async function main() { + const inst = await load(); + const result = invokeKCLRun(inst, { + filename: "test.k", + source: ` +schema Person: + name: str + +p = Person {name = "Alice"}`, + }); + console.log(result); +} + +main(); +``` + +The output is + +```yaml +p: + name: Alice +``` + +The code example can be found [here](https://github.com/kcl-lang/lib/tree/main/wasm/examples/node). + +## Rust + +In Rust, we use `wasmtime` as an example, and of course, you can also use other runtime that supports WASI to accomplish this. + +Install the dependency + +```shell +cargo add kcl-wasm-lib --git https://github.com/kcl-lang/lib +cargo add anyhow +``` + +Write the code + +```rust +use anyhow::Result; +use kcl_wasm_lib::{KCLModule, RunOptions}; + +fn main() -> Result<()> { + let opts = RunOptions { + filename: "test.k".to_string(), + source: "a = 1".to_string(), + }; + // Note replace your KCL wasm module path. + let mut module = KCLModule::from_path("path/to/kcl.wasm")?; + let result = module.run(&opts)?; + println!("{}", result); + Ok(()) +} +``` + +The output is + +```yaml +a: 1 +``` + +The code example can be found [here](https://github.com/kcl-lang/lib/tree/main/wasm/examples/rust). + +## Go + +In Go, we use `wasmtime` as an example, and of course, you can also use other runtime that supports WASI to accomplish this. + +Write the code, and the code of package `github.com/kcl-lang/wasm-lib/pkg/module` can be found [here](https://github.com/kcl-lang/lib/blob/main/wasm/examples/go/pkg/module/module.go) + +```go +package main + +import ( + "fmt" + + "github.com/kcl-lang/wasm-lib/pkg/module" +) + +func main() { + m, err := module.New("path/to/kcl.wasm") + if err != nil { + panic(err) + } + result, err := m.Run(&module.RunOptions{ + Filename: "test.k", + Source: "a = 1", + }) + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + +The output is + +```yaml +a: 1 +``` + +The code example can be found [here](https://github.com/kcl-lang/lib/tree/main/wasm/examples/go). diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/_category_.json new file mode 100644 index 000000000..fcdc7f102 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "集成开发环境", + "position": 2 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/index.md new file mode 100644 index 000000000..36f70cd97 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/index.md @@ -0,0 +1,7 @@ +# IDE + +我们为 KCL 提供了两种简单的 IDE 插件。您可以通过以下链接获得更多帮助信息: + +- IntelliJ 插件: https://github.com/kcl-lang/intellij-kcl +- VSCode 插件: https://github.com/kcl-lang/vscode-kcl +- NeoVim 插件: https://github.com/kcl-lang/kcl.nvim diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/intellij.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/intellij.md new file mode 100644 index 000000000..bc3cdd317 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/intellij.md @@ -0,0 +1,63 @@ +--- +sidebar_position: 3 +--- + +# IntelliJ IDEA + +## 快速开始 + +- **1.** [安装 KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) 并检查 `kcl` 和 `kcl-language-server` 命令在您的 PATH 中: + 在 MacOs 和 Linux中: + + ```bash + which kcl + which kcl-language-server + ``` + + 在 Windows 中: + + ```bash + where kcl + where kcl-language-server + ``` + +- **2.** 安装 [IntelliJ IDEA KCL 插件](https://plugins.jetbrains.com/plugin/23378-kcl). +- **3.** 重新打开 IntelliJ IDEA 并创建一个 KCL 文件验证 IDE 插件功能 + +## Features + +此插件基于 LSP 提供了许多编码帮助,包括以下功能: + +- **高亮:** 语法和语义高亮 +- **补全:** 关键字,变量名,属性等补全 +- **跳转:** schema 定义,变量,schema 属性等跳转 +- **大纲:** 显示 KCL 文件中的 schema 和 变量定义 +- **悬停:** Identifier 信息 (type 和 schema 文档) +- **诊断:** KCL 文件中的警告和错误信息 +- **快速修复:** 对一些错误进行快速修复 +- **内联提示:** 变量类型,函数和 schema 参数等提示 +- **格式化:** 格式化一个 KCL 文件或代码片段 + +其他一些有用的功能,如代码重构和智能感知等正在开发中。 + +## 最小依赖 + +我们建议您使用最新版本的 KCL,但此扩展所需的 KCL 最低版本为 v0.4.6。如果您使用的是更早期版本,则此扩展可能无法正常工作。 + +IntelliJ IDEA 的最低版本为 2022.1 + +## 已知问题 + +[详见](https://github.com/kcl-lang/kcl/issues) + +## 寻求帮助 + +如果扩展没有如您所期望的那样工作,请通过[社区](https://kcl-lang.io/docs/community/intro/support)与我们联系和寻求帮助。 + +## 参与贡献 + +目前我们正在积极改进 KCL IDE 插件体验,欢迎参考[贡献指南](https://kcl-lang.io/docs/community/contribute) 一起共建! + +## 许可 + +Apache License 2.0 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/neovim.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/neovim.md new file mode 100644 index 000000000..f8c5c3581 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/neovim.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 2 +--- + +# NeoVim + +- NeoVim KCL 插件: [https://github.com/kcl-lang/kcl.nvim](https://github.com/kcl-lang/kcl.nvim) + +![kcl.nvim](/img/docs/tools/Ide/neovim/overview.png) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/vs-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/vs-code.md new file mode 100644 index 000000000..b2521c25d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/Ide/vs-code.md @@ -0,0 +1,73 @@ +--- +sidebar_position: 1 +--- + +# Visual Studio Code + +## 快速开始 + +- **1.** [安装 KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) 并检查 `kcl` 和 `kcl-language-server` 命令在您的 PATH 中: + 在 MacOs 和 Linux中: + + ```bash + which kcl + which kcl-language-server + ``` + + 在 Windows 中: + + ```bash + where kcl + where kcl-language-server + ``` + +- **2.** 安装 [VS Code KCL 插件](https://marketplace.visualstudio.com/items?itemName=kcl.kcl-vscode-extension). 需要您的 VS Code 版本大于 1.50+ +- **3.** 重新打开 VS Code 并创建一个 KCL 文件验证 IDE 插件功能 + +## 特性 + +此扩展提供了一些 KCL 编码帮助,包括以下功能: + +- **语法高亮** + ![Highlight](/img/docs/tools/Ide/vs-code/Highlight.png) +- **跳转:** 跳转至定义,如 schema,schema 属性, 变量,map key 等 + ![Goto Definition](/img/docs/tools/Ide/vs-code/GotoDef.gif) +- **补全:** 代码补全,如关键字, 点(`.`) 变量,schema 属性等 + ![Completion](/img/docs/tools/Ide/vs-code/Completion.gif) +- **大纲:** 显示 KCL 文件中的 schema 和 变量定义 + ![Outline](/img/docs/tools/Ide/vs-code/Outline.gif) +- **悬停**: 悬停提示 Identifer 的信息,如类型,函数签名和文档等 + ![Hover](/img/docs/tools/Ide/vs-code/Hover.gif) +- **诊断:** 警告和错误信息 + ![Diagnostics](/img/docs/tools/Ide/vs-code/Diagnostics.gif) + +> 提示:您可以通过安装 [Error Lens 插件](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens) 来增强诊断效果 + +- **格式化:** 格式化一个 KCL 文件或代码片段 + ![Format](/img/docs/tools/Ide/vs-code/Format.gif) +- **快速修复:** 快速修复一些诊断信息 + ![Qucik Fix](/img/docs/tools/Ide/vs-code/QuickFix.gif) +- **内联提示:** 内链提示变量类型和其他语义信息 + ![Inlay Hint](/img/docs/tools/Ide/vs-code/Inlayhint.png) + +其他一些有用的功能,如代码重构和智能感知等正在开发中。 + +## 最小依赖 + +我们建议您使用最新版本的 KCL,但此扩展所需的 KCL 最低版本为 v0.4.6。如果您使用的是更早期版本,则此扩展可能无法正常工作。 + +## 已知问题 + +[详见](https://github.com/kcl-lang/kcl/issues) + +## 寻求帮助 + +如果扩展没有如您所期望的那样工作,请通过[社区](https://kcl-lang.io/docs/community/intro/support)与我们联系和寻求帮助。 + +## 参与贡献 + +目前我们正在积极改进 KCL IDE 插件体验,欢迎参考[贡献指南](https://kcl-lang.io/docs/community/contribute) 一起共建! + +## 许可 + +Apache License 2.0 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/_category_.json new file mode 100644 index 000000000..5170334a3 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "工具", + "position": 3 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/_category_.json new file mode 100644 index 000000000..8fac9ad81 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "命令行工具", + "position": 1 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/index.md new file mode 100644 index 000000000..f754b5cad --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/index.md @@ -0,0 +1,3 @@ +# 命令行工具 + +KCL 提供了 IDE 插件、丰富的语言工具和 OpenAPI 工具。通过这些工具,可以提供一整套解决方案,包括配置语言、模型界面、自动化工具和最佳实践。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/_category_.json new file mode 100644 index 000000000..b22440b71 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "KCL 语言工具", + "position": 2 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/docgen.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/docgen.md new file mode 100644 index 000000000..9aa3e9857 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/docgen.md @@ -0,0 +1,162 @@ +--- +sidebar_position: 2 +--- + +# 文档生成工具 + +KCL 命令行工具支持从 KCL 源码中一键提取模型文档,并支持 Markdown, HTML, OpenAPI 等输出格式。本文介绍 KCL 语言的文档规范,举例说明如何使用 KCL 文档生成工具提取文档。 + +## KCL 语言的文档规范 + +KCL文件的文档主要包含如下两个部分: + +- 当前 KCL 模块的文档:对当前 KCL 文件的说明 +- KCL 文件内包含的所有 Schema 的文档:对当前 Schema 的说明,其中包含 Schema 描述、Schema 各属性的描述、Examples 三部分,具体格式如下: + +1. Schema 描述 + +```python +"""这是Schema一个简短的描述信息 +""" +``` + +2. Schema 各属性的描述:包含属性描述、属性类型、默认值、是否可选 + +```python +""" +Attributes +---------- +x : type, default is a, optional. + Description of parameter `x`. +y : type, default is b, required. + Description of parameter `y`. +""" +``` + +其中,使用 `----------` 表示 `Attributes` 为一个标题(`-` 符号长度与标题长度保持一致),属性名称与属性类型用冒号 `:` 分隔,属性的说明另起一行并增加缩进进行书写。属性的默认值说明跟在属性类型之后使用逗号 `,` 分隔,书写为 `default is {默认值}` 形式,此外需要说明属性是否为可选/必选,对于可选属性在默认值之后书写 `optional`,对于必选属性在默认值之后书写 `required`。 + +3. Examples + +```python +""" +Examples +-------- +val = Schema { + name = "Alice" + age = 18 +} +""" +``` + +此外,KCL 文档字符串语法应采用 [re-structured text (reST)](https://docutils.sourceforge.io/rst.html) 语法子集,并使用 [Sphinx](https://www.sphinx-doc.org/en/master/) 渲染呈现。 + +## 从 KCL 源码生成文档 + +使用 `kcl doc generate` 命令,从用户指定的文件或目录中提取文档,并输出到指定目录。 + +为当前 KCL 包生成 Markdown 文档到 `/docs` 目录 (包含 kcl.mod 文件) + +```shell +kcl doc generate +``` + +为当前 KCL 包生成 HTML 文档到 `/docs` 目录 (包含 kcl.mod 文件) + +```shell +kcl doc generate --format html +``` + +指定 KCL 包路径生成 Markdown 文档到 `/docs` 目录 + +```shell +kcl doc generate --file-path +``` + +指定 KCL 包路径生成 Markdown 文档并保存到 `<目标目录>`。 + +```shell +kcl doc generate --file-path --target +``` + +如果您遇到了 HTML 或者 Markdown 等输出格式问题,比如 `|`, `\n` 等符号显示错误,您可以添加 `--escape-html` 标志 + +```shell +kcl doc generate --escape-html +``` + +## 文档工具附录 + +### 常见的 reST 概念 + +对于 reST 格式的文档,段落和缩进很重要,新段落用空白行标记,缩进即为表示输出中的缩进。可以使用如下方式表示字体样式: + +- \*斜体\* +- \*\*粗体\*\* +- \`\`等宽字体\`\` + +参考 [reST 文档](https://docutils.sourceforge.io/rst.html)获得更多帮助。 + +## 参数说明 + +### kcl doc + +```shell +This command shows documentation for KCL modules or symbols. + +Usage: + kcl doc [command] + +Aliases: + doc, d + +Examples: + # Generate document for current package + kcl doc generate + +Available Commands: + generate Generates documents from code and examples + +Flags: + -h, --help help for doc + +Use "kcl doc [command] --help" for more information about a command. +``` + +### kcl doc generate + +```shell +This command generates documents for KCL modules. + +Usage: + kcl doc generate [flags] + +Aliases: + generate, gen, g + +Examples: + # Generate Markdown document for current package + kcl doc generate + + # Generate Markdown document for current package and escape the HTML symbols | to \|, \n to
, etc. + kcl doc generate --escape-html + + # Generate Html document for current package + kcl doc generate --format html + + # Generate Markdown document for specific package + kcl doc generate --file-path + + # Generate Markdown document for specific package to a + kcl doc generate --file-path --target + +Flags: + --escape-html Whether to escape html symbols when the output format is markdown. Always scape when the output format is html. Default to false. + --file-path string Relative or absolute path to the KCL package root when running kcl-doc command from + outside of the KCL package root directory. + If not specified, the current work directory will be used as the KCL package root. + --format string The document format to generate. Supported values: markdown, html, openapi. (default "md") + -h, --help help for generate + --ignore-deprecated Do not generate documentation for deprecated schemas. + --target string If not specified, the current work directory will be used. A docs/ folder will be created under the target directory. + --template string The template directory based on the KCL package root. If not specified, the built-in templates will be used. +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/fmt.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/fmt.md new file mode 100644 index 000000000..2ada7ba5e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/fmt.md @@ -0,0 +1,89 @@ +--- +sidebar_position: 3 +--- + +# 代码格式化工具 + +KCL 支持通过内置的命令行工具一键格式化多个 KCL 文件文档。本文展示 KCL 编码风格和 KCL 格式化工具的使用方式。 + +## KCL 编码风格 + +KCL 格式化对文件的修改样式具体见 KCL 编码风格:[Style Guide for KCL Code](/docs/reference/lang/spec/codestyle) + +## 使用方式 + +- 单文件格式化 + +```shell +kcl fmt your_config.k +``` + +- 文件夹内多文件格式化 + +```shell +kcl fmt your_config_path -R +``` + +- 命令行参数 + - `-R|--recursive` 设置是否递归遍历子文件夹 + - `-w|--fmt-output` 设置是否输出到标准输出流,不加 `-w` 表示原地格式化 KCL 文件 + +## 格式化文件效果展示 + +- 格式化前 + +```py +import math +mixin DeploymentMixin: + service:str ="my-service" +schema DeploymentBase: + name: str + image : str +schema Deployment[replicas] ( DeploymentBase ) : + mixin[DeploymentMixin] + replicas : int = replicas + command: [str ] + labels: {str: str} +deploy = Deployment(replicas = 3){} +``` + +- 格式化后 + +```py +import math + +mixin DeploymentMixin: + service: str = "my-service" + +schema DeploymentBase: + name: str + image: str + +schema Deployment[replicas](DeploymentBase): + mixin [DeploymentMixin] + replicas: int = replicas + command: [str] + labels: {str:str} + +deploy = Deployment(replicas=3) {} + +``` + +## 参数说明 + +```shell +This command formats all kcl files of the current crate. + +Usage: + kcl fmt [flags] + +Examples: + # Format the single file + kcl fmt /path/to/file.k + + # Format all files in this folder recursively + kcl fmt ./... + +Flags: + -h, --help help for fmt +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/import.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/import.md new file mode 100644 index 000000000..81af8837e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/import.md @@ -0,0 +1,62 @@ +--- +sidebar_position: 4 +--- + +# 数据和结构导入工具 + +## 简介 + +KCL 支持内置的 `kcl import` 工具将其他格式的数据或者结构定义导入到 KCL 中,目前 KCL 支持 JSON, YAML, Go Structure, JsonSchema, Terraform Provider Schema, OpenAPI, Kubernetes CRD 导入为 KCL 配置或 Schema 定义。 + +## 参数说明 + +```shell +This command converts other formats to KCL file. + +Supported conversion modes: +- json: convert JSON data to KCL data +- yaml: convert YAML data to KCL data +- toml: convert TOML data to KCL data +- gostruct: convert Go struct to KCL schema +- jsonschema: convert JSON schema to KCL schema +- terraformschema: convert Terraform schema to KCL schema +- openapi: convert OpenAPI spec to KCL schema +- crd: convert Kubernetes CRD to KCL schema +- auto: automatically detect the input format + +Usage: + kcl import [flags] + +Examples: + # Generate KCL models from OpenAPI spec + kcl import -m openapi swagger.json + + # Generate KCL models from Kubernetes CRD + kcl import -m crd crd.yaml + + # Generate KCL models from JSON + kcl import data.json + + # Generate KCL models from YAML + kcl import data.yaml + + # Generate KCL models from TOML + kcl import data.toml + + # Generate KCL models from JSON Schema + kcl import -m jsonschema schema.json + + # Generate KCL models from Terraform provider schema + kcl import -m terraformschema schema.json + + # Generate KCL models from Go structs + kcl import -m gostruct schema.go + +Flags: + -f, --force Force overwrite output file + -h, --help help for import + -m, --mode string Specify the import mode. Default is mode (default "auto") + -o, --output string Specify the output file path + -p, --package string The package to save the models. Default is models (default "models") + -s, --skip-validation Skips validation of spec prior to generation +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/index.md new file mode 100644 index 000000000..b1f8ce930 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/index.md @@ -0,0 +1,3 @@ +# KCL 语言工具 + +KCL 不仅提供了 kcl 命令编译和执行配置程序,还提供了 fmt、lint、test、vet、doc 等配套的辅助工具。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/lint.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/lint.md new file mode 100644 index 000000000..ecc7d4d57 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/lint.md @@ -0,0 +1,79 @@ +--- +sidebar_position: 5 +--- + +# 代码风格检查工具 + +KCL 支持通过内置的命令行工具对 KCL 代码进行检查,并支持多种输出格式。本文档展示 KCL Lint 工具的使用方式。 + +## 示例 + +### 工程结构 + +```text +. +└── Test + └── kcl.mod + └── a.k + └── b.k + └── dir + └── c.k + └── test.k +``` + +`a.k`,`b.k`,`c.k`,`test.k` 为测试的 kcl 文件。 + +命令: + +```shell +kcl lint your_config.k +``` + +或 + +```shell +kcl lint your_config_path +``` + +## 参数说明 + +```shell +This command lints the kcl code. 'kcl lint' takes multiple input for arguments. + +For example, 'kcl lint path/to/kcl.k' will lint the file named path/to/kcl.k + +Usage: + kcl lint [flags] + +Examples: + # Lint a single file and output YAML + kcl lint path/to/kcl.k + + # Lint multiple files + kcl lint path/to/kcl1.k path/to/kcl2.k + + # Lint OCI packages + kcl lint oci://ghcr.io/kcl-lang/helloworld + + # Lint the current package + kcl lint + +Flags: + -D, --argument stringArray Specify the top-level argument + -d, --debug Run in debug mode + -n, --disable_none Disable dumping None values + -E, --external strings Specify the mapping of package name and path where the package is located + --format string Specify the output format (default "yaml") + -h, --help help for lint + --no_style Set to prohibit output of command line waiting styles, including colors, etc. + -o, --output string Specify the YAML/JSON output file path + -O, --overrides strings Specify the configuration override path and value + -S, --path_selector strings Specify the path selectors + -q, --quiet Set the quiet mode (no output) + -Y, --setting strings Specify the command line setting files + -H, --show_hidden Display hidden attributes + -k, --sort_keys Sort output result keys + -r, --strict_range_check Do perform strict numeric range checks + -t, --tag string Specify the tag for the OCI or Git artifact + -V, --vendor Run in vendor mode +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/overview.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/overview.md new file mode 100644 index 000000000..1bc414767 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/overview.md @@ -0,0 +1,61 @@ +--- +sidebar_position: 0 +--- + +# 概览 + +KCL 工具链是 KCL 语言的工具集合,旨在提升 KCL 的批量迁移、编写、编译和测试的效率。 + +| 类别 | 工具名称 | 说明 | +| ---------- | ------------------------ | ------------------------------------------------------- | +| 主工具集 | **kcl** (kcl run 的别称) | kcl 命令行工具提供对基于 KCL 语言的配置编写、编译和运行 | +| | kcl run | kcl 命令行工具提供对基于 KCL 语言的配置编写、编译和运行 | +| | kcl doc | 解析KCL代码并生成文档 | +| | kcl fmt | 格式化KCL代码 | +| | kcl import | 导入其他数据和模式到KCL | +| | kcl lint | 检查KCL的代码风格 | +| | kcl mod | KCL模块相关功能和包管理 | +| | kcl play | 在本地运行KCL playground | +| | kcl registry | KCL注册表相关功能 | +| | kcl server | 在本地运行KCL REST服务器 | +| | kcl test | 运行KCL中的单元测试 | +| | kcl vet | 使用KCL验证JSON和YAML等数据文件 | +| ide 插件集 | IntelliJ IDEA KCL 插件 | 提供 IntelliJ IDEA 平台的 KCL 编写、编译辅助 | +| | NeoVim KCL 插件 | 提供 NeoVim 平台的 KCL 编写、编译辅助 | +| | VS Code KCL 插件 | 提供 VS Code 平台的 KCL 编写、编译辅助 | + +## 参数说明 + +```shell +The KCL Command Line Interface (CLI). + +KCL is an open-source, constraint-based record and functional language that +enhances the writing of complex configurations, including those for cloud-native +scenarios. The KCL website: https://kcl-lang.io + +Usage: + kcl [command] + +Available Commands: + clean KCL clean tool + completion Generate the autocompletion script for the specified shell + doc KCL document tool + fmt KCL format tool + help Help about any command + import KCL import tool + lint Lint KCL codes. + mod KCL module management + play Open the kcl playground in the browser. + registry KCL registry management + run Run KCL codes. + server Run a KCL server + test KCL test tool + version Show version of the KCL CLI + vet KCL validation tool + +Flags: + -h, --help help for kcl + -v, --version version for kcl + +Use "kcl [command] --help" for more information about a command. +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/run.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/run.md new file mode 100644 index 000000000..a3b86be69 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/run.md @@ -0,0 +1,60 @@ +--- +sidebar_position: 1 +--- + +# 运行 KCL 代码 + +## 参数说明 + +```shell +This command runs the kcl code and displays the output. 'kcl run' takes multiple input for arguments. + +For example, 'kcl run path/to/kcl.k' will run the file named path/to/kcl.k + +Usage: + kcl run [flags] + +Aliases: + run, r + +Examples: + # Run a single file and output YAML + kcl run path/to/kcl.k + + # Run a single file and output JSON + kcl run path/to/kcl.k --format json + + # Run a single file and output TOML + kcl run path/to/kcl.k --format toml + + # Run multiple files + kcl run path/to/kcl1.k path/to/kcl2.k + + # Run OCI packages + kcl run oci://ghcr.io/kcl-lang/helloworld + + # Run remote Git repo + kcl run https://github.com/kcl-lang/flask-demo-kcl-manifests + + # Run the current package + kcl run + +Flags: + -D, --argument stringArray Specify the top-level argument + -d, --debug Run in debug mode + -n, --disable_none Disable dumping None values + -E, --external strings Specify the mapping of package name and path where the package is located + --format string Specify the output format (default "yaml") + -h, --help help for run + --no_style Set to prohibit output of command line waiting styles, including colors, etc. + -o, --output string Specify the YAML/JSON output file path + -O, --overrides strings Specify the configuration override path and value + -S, --path_selector strings Specify the path selectors + -q, --quiet Set the quiet mode (no output) + -Y, --setting strings Specify the command line setting files + -H, --show_hidden Display hidden attributes + -k, --sort_keys Sort output result keys + -r, --strict_range_check Do perform strict numeric range checks + -t, --tag string Specify the tag for the OCI or Git artifact + -V, --vendor Run in vendor mode +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/test.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/test.md new file mode 100644 index 000000000..e77305445 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/test.md @@ -0,0 +1,187 @@ +--- +sidebar_position: 6 +--- + +# 测试工具 + +## 简介 + +KCL 支持通过内置的 `kcl test` 命令行工具提供了简易的测试框架。每个目录下的全部 KCL 文件是一个测试整体,每个 `_test.k` 中 `test_` 开头的 lambda 函数是一个测试用例。 + +## 使用方式 + +假设有 hello.k 文件,代码如下: + +```python +schema Person: + name: str = "kcl" + age: int = 1 + + check: + 0 <= age <= 120, "age must be in [0, 120]" + +hello = Person { + name = "hello kcl" + age = 102 +} +``` + +构造 hello_test.k 测试文件,内容如下: + +```python +test_person = lambda { + a = Person{} + assert a.name == 'kcl' +} +test_person_age = lambda { + a = Person{} + assert a.age == 1 +} +test_person_ok = lambda { + a = Person{} + assert a.name == "kcl" + assert a.age == 1 +} +``` + +然后再目录下执行 `kcl test` 命令: + +```shell +kcl test +``` + +输出为: + +```shell +test_person: PASS (2ms) +test_person_age: PASS (1ms) +test_person_ok: PASS (1ms) +-------------------------------------------------------------------------------- +PASS: 3/3 +``` + +## 失败的测试 + +将 hello_test.k 测试代码修改如下,构造失败的测试: + +```python +test_person = lambda { + a = Person{} + assert a.name == 'kcl2' +} +test_person_age = lambda { + a = Person{} + assert a.age == 123 +} +test_person_ok = lambda { + a = Person{} + assert a.name == "kcl2" + assert a.age == 1 +} +``` + +执行命令 + +```shell +kcl test +``` + +测试输出的错误如下: + +```shell +test_person: FAIL (6ms) +EvaluationError + --> hello_test.k:3:1 + | +3 | assert a.name == 'kcl2' + | + | + + +test_person_age: FAIL (3ms) +EvaluationError + --> hello_test.k:7:1 + | +7 | assert a.age == 123 + | + | + + +test_person_ok: FAIL (2ms) +EvaluationError + --> hello_test.k:11:1 + | +11 | assert a.name == "kcl2" + | + | + + +-------------------------------------------------------------------------------- +FAIL: 3/3 +``` + +如果我们想要正确测试错误情况并检查错误消息,我们可以使用 `runtime.catch` 函数。 + +```python +import runtime + +test_person_age_check_error_message = lambda { + msg = runtime.catch(lambda { + a = Person {age = 123} + }) + assert msg == "age must be in [0, 120]" +} +``` + +运行命令 + +```shell +kcl test +``` + +输出: + +```shell +test_person_age_check_error_message: PASS (2ms) +-------------------------------------------------------------------------------- +PASS: 1/1 +``` + +## 参数说明 + +- `kcl test path` 执行指定目录的测试, 当前目录可以省略该参数 +- `kcl test --run=regexp` 可以执行匹配模式的测试 +- `kcl test ./...` 递归执行子目录的单元测试 + +```shell +This command automates testing the packages named by the import paths. + +'KCL test' re-compiles each package along with any files with names matching +the file pattern "*_test.k". These additional files can contain test functions +that starts with "test_*". + +Usage: + kcl test [flags] + +Aliases: + test, t + +Examples: + # Test whole current package recursively + kcl test ./... + + # Test package named 'pkg' + kcl test pkg + + # Test with the fail fast mode. + kcl test ./... --fail-fast + + # Test with the regex expression filter 'test_func' + kcl test ./... --run test_func + + +Flags: + --fail-fast Exist when meet the first fail test case in the test process. + -h, --help help for test + --run string If specified, only run tests containing this string in their names. +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/vet.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/vet.md new file mode 100644 index 000000000..9b9846abb --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/kcl/vet.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 7 +--- + +# 校验工具 + +## 简介 + +KCL 支持通过内置的 `kcl vet` 命令行工具提供了基本的配置数据校验能力,可以编写 KCL schema 对输入的 JSON/YAML 格式文件进行类型以及数值的校验。 + +## 使用方式 + +假设有 data.json 文件,代码如下: + +```json +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} +``` + +构造 schema.k 校验文件,内容如下: + +```py +schema User: + name: str + age: int + message?: str + data: Data + labels: {str:} + hc: [int] + + check: + age > 10 + +schema Data: + id: int + value: str +``` + +在目录下执行如下命令 + +```shell +kcl vet data.json schema.k +``` + +## 指定校验的 schema + +当校验的 KCL 文件中存在多个 schema 定义时,kcl vet 工具会默认取第一个 schema 定义进行校验,如果需要指定校验的 schema,可以使用 `-s|--schema` 参数 + +```shell +kcl vet data.json schema.k -s User +``` + +## 命令行参数 + +```shell +This command validates the data file using the kcl code. + +Usage: + kcl vet [flags] + +Examples: + # Validate the JSON data using the kcl code + kcl vet data.json code.k + + # Validate the YAML data using the kcl code + kcl vet data.yaml code.k --format yaml + + # Validate the JSON data using the kcl code with the schema name + kcl vet data.json code.k -s Schema + + +Flags: + -a, --attribute_name string Specify the validate config attribute name. + --format string Specify the validate data format. e.g., yaml, json. Default is json + -h, --help help for vet + -s, --schema string Specify the validate schema. +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/_category_.json new file mode 100644 index 000000000..5df621d89 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "OpenAPI 工具", + "position": 3 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/crd-to-kcl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/crd-to-kcl.md new file mode 100644 index 000000000..bab897f78 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/crd-to-kcl.md @@ -0,0 +1,118 @@ +# CRD to KCL + +命令 + +```shell +kcl import -m crd -o ${the_kcl_files_output_dir} -s ${your_CRD.yaml} +``` + +# 示例 + +- 输入文件:test_crontab_CRD.yaml: + +```yaml +# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: crontabs.stable.example.com +spec: + # group name to use for REST API: /apis// + group: stable.example.com + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: crontabs + # singular name to be used as an alias on the CLI and for display + singular: crontab + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: CronTab + # shortNames allow shorter string to match your resource on the CLI + shortNames: + - ct + preserveUnknownFields: false + validation: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + cronSpec: + type: string + image: + type: string + replicas: + type: integer +``` + +- 命令 + +```shell +kcl-openapi generate model -f test_crontab_CRD.yaml -t ~/ --skip-validation --crd +``` + +- 输出文件: ~/models/stable_example_com_v1_cron_tab.k + +```python +""" +This file was generated by the KCL auto-gen tool. DO NOT EDIT. +Editing this file might prove futile when you re-run the KCL auto-gen generate command. +""" +import kusion_kubernetes.apimachinery.apis + + +schema CronTab: + """stable example com v1 cron tab + + Attributes + ---------- + apiVersion : str, default is "stable.example.com/v1", required + APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + kind : str, default is "CronTab", required + Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + metadata : apis.ObjectMeta, default is Undefined, optional + metadata + spec : StableExampleComV1CronTabSpec, default is Undefined, optional + spec + """ + + + apiVersion: "stable.example.com/v1" = "stable.example.com/v1" + + kind: "CronTab" = "CronTab" + + metadata?: apis.ObjectMeta + + spec?: StableExampleComV1CronTabSpec + + +schema StableExampleComV1CronTabSpec: + """stable example com v1 cron tab spec + + Attributes + ---------- + cronSpec : str, default is Undefined, optional + cron spec + image : str, default is Undefined, optional + image + replicas : int, default is Undefined, optional + replicas + """ + + + cronSpec?: str + + image?: str + + replicas?: int +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/openapi-to-kcl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/openapi-to-kcl.md new file mode 100644 index 000000000..38a62f88f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/openapi-to-kcl.md @@ -0,0 +1,64 @@ +# OpenAPI to KCL + +命令 + +```shell +kcl import -m openapi -o ${the_kcl_files_output_dir} ${your_open_api_spec.yaml} +``` + +示例: + +- 输入文件:test_open_api_spec.yaml: + +```yaml +definitions: + v1.TestInt: + type: object + properties: + name: + type: string + format: int-or-string + required: + - name + x-kcl-type: + import: + package: v1.test_int + alias: test_int + type: TestInt +swagger: "2.0" +info: + title: KCL + version: v0.0.2 +paths: {} +``` + +- 命令: + +```shell +kcl import -m openapi -o ~/ -s test_open_api_spec.yaml +``` + +- 输出:~/models/v1/test_int.k + +```python +""" +This is the test_int module in v1 package. +This file was generated by the KCL auto-gen tool. DO NOT EDIT. +Editing this file might prove futile when you re-run the KCL auto-gen generate command. +""" + + +schema TestInt: + """v1 test int + + Attributes + ---------- + name : int | str, default is Undefined, required + name + """ + + + name: int | str + + +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/spec.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/spec.md new file mode 100644 index 000000000..aee9fc92a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/openapi/spec.md @@ -0,0 +1,424 @@ +# KCL OpenAPI 规范 + +[OpenAPI](https://www.openapis.org/) 允许 API 提供方规范地描述 API 操作和模型,并基于它生成自动化工具和特定语言的客户端。 + +## KCL OpenAPI 文件结构 + +依据 OpenAPI 3.0 规范,OpenAPI 文件中应至少包含 openapi、components、 info、paths 四种根节点对象,KCL OpenAPI 聚焦于其中模型定义的部分,即 OpenAPI 文件中的 `definitions`,而描述操作的 Restful API 部分(即 OpenAPI 文件中的 `paths`)则不属于 KCL OpenAPI 定义的范畴。 +​ + +注:除以上列出的节点外,OpenAPI 官方规范还支持 servers、security、tags、externalDocs 四种可选的根节点,但都不是 KCL OpenAPI 所关心的,因此用户无需填写这部分内容,即使填写了也不会产生任何影响。 +​ + +| OpenAPI 顶层对象 | 类型 | 含义 | KCL OpenAPI 工具支持情况 | +| ---------------- | ----------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| swagger | string | openapi 版本信息 | 必填项,目前支持 openapi 2.0,即合法取值为 "2.0" | +| definitions | Definition Object | 模型定义 | 必填项 | +| info | Info Object | 当前 API 文件的元数据信息,例如标题、描述信息、版本、开源协议等 | 必填项,定义当前 OpenAPI 文件的基本信息,不会输出到 KCL 代码,但可用于 Swagger-UI 工具可视化展示 | + +为方便初学者快速理解,下面给出一个典型的 KCL OpenAPI 文件(截取自 swagger example [Petstore](https://petstore.swagger.io/))应包含的节点图示。KCL OpenAPI 工具重点关注其中的 definitions 节点,可以看到文件中定义了两个模型(Pet 和 Category),并且 Pet 模型中包含三个属性(name、id、category) + +## KCL schema + +KCL 中使用 schema 结构来定义配置数据的“类型”,关于 KCL schema,可参考文档:传送门 +在 definitions 节点下新增 definition 元素,即可定义 KCL schema. +示例: +下例在 KCL 代码中定义了 Pet、Category 两个 schema,同样地,其对应的 OpenAPI 也在 definitions 节点下包含这两个模型的描述。 + +```python +# KCL schema: +schema Pet: + name: str + id?: int + category?: Category + +schema Category: + name?: str + +# 对应的 OpenAPI 描述 +{ + "definitions": { + "Pet": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "category": { + "$ref": "#/definitions/Category" + } + }, + "required": [ + "name" + ] + }, + "Category": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + }, + "swagger": "2.0", + "info": { + "title": "demo", + "version": "v1" + } +} + +``` + +### schema 名称 + +在 KCL 中,schema 名称紧跟在 schema 关键字后声明,在 OpenAPI 中,模型的名称通过 definition 元素的 key 来定义。 + +### schema 类型 + +KCL schema 在 OpenAPI 中的类型为 "object". 例如上例中 "Pet" 的 "type" 值应为 "object". + +### schema 属性 + +KCL schema 中可以定义若干属性,属性的声明一般包含如下几部分: + +- 属性注解:可选,以 @ 开头,例如 @deprecated 注解表示属性被废弃 +- 属性名称:必须 +- 属性 optional 修饰符(?):可选,带问号表示当前属性为可选属性,可以不被赋值。反之,不带问号表示必填属性 +- 属性类型:必须,可以是基本数据类型,也可以是 schema 类型, 或者是前述两种类型的并集 +- 属性默认值:非必须 + +它们与 OpenAPI 规范的对应关系如下: + +| KCL schema 属性元素 | OpenAPI 元素 | +| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | +| 属性注解 | 暂不支持,计划扩展一个 deprecate 字段用于描述 deprecated 注解 | | +| 属性名称 | properties 节点下,每个属性的 key 即为属性名称 | +| 属性 optional 修饰符(?) | 模型节点下,通过 required 字段列出该模型的所有必填属性的名称,未被列出的属性即为 optional | +| 属性类型 | 属性节点下,设置 type + format 可以标识属性的基本类型,如果是 schema 类型则用 $ref 字段表示,类型 union 则由扩展字段 x-kcl-types 来标识,此外,属性节点的 enum、pattern 也可以用于表示 KCL 类型。 | +| KCL-OpenAPI 关于类型的对照关系,详见“基本数据类型”小节 | | +| 属性默认值 | 属性节点下,设置 default 字段即可为属性设置默认值 | + +示例: +下例中 Pet 模型包含了 2 个属性:name(string 类型,必填属性,无注解,无默认值)、id(int64 类型,无注解,非必填,默认值为 -1) + +```python +# KCL schema Pet,包含两个属性 name 和 id +schema Pet: + name: str + id?: int = -1 + +# 对应的 OpenAPI 文档 +{ + "definitions": { + "Pet": { + "type": "object", + "properties": { + "name": { + "type": "string", + }, + "id": { + "type": "integer", + "format": "int64", + "default": -1 + } + }, + "required": [ + "name" + ], + } + }, + "swagger": "2.0", + "info": { + "title": "demo", + "version": "v1" + } +} +``` + +### schema 索引签名 + +KCL schema 允许定义索引签名,用于定义属性名不固定的 dict,起到静态模板的作用。具体来说,KCL schema 索引签名包含如下几个元素: + +- 索引签名中 key 的类型:在方括号中声明,必须是基础类型 +- 索引签名中 value 的类型:在冒号后声明,可以是任意合法的 KCL 类型 +- 索引签名中的省略符:在方括号中,key 类型之前声明,使用"..."表示。如果带有该符号,表示该索引签名只用于约束未在 schema 中定义的属性;否则,表示 schema 中所有已定义和未定义属性都收到该索引签名的约束。 +- 索引签名中 key 的别名:在方括号中,紧随左方括号之后声明,使用名称 + 冒号表示,该别名可用于按名称引用索引签名 +- 索引签名的默认值:可以为索引签名设置默认值 + +在 OpenAPI 中,可以借助在模型节点的 `additionalProperties` 字段描述某些 key 为 string 的索引签名。但对于 KCL 索引签名中非 string 类型的 dict key、索引签名 key 的 check 校验,在 OpenAPI 规范没有对等的描述。它们与 OpenAPI 规范的对应关系如下: + +| KCL 索引签名元素 | OpenAPI 元素 | +| ----------------------- | ---------------------------------------------------------------------- | +| 索引签名中 key 的类型 | OpenAPI 仅支持 key 为 string 类型,无法自定义 | +| 索引签名中 value 的类型 | 模型节点的下 additionalProperties 下的 "type" 字段 | +| 索引签名中的省略符 | OpenAPI 中表示索引签名时,只能表示 KCL 中带有省略符的情况 | +| 索引签名中 key 的别名 | OpenAPI 中不支持为索引签名定义 key 别名,(预计通过扩展支持:x-alias) | +| 索引签名的默认值 | 目前不支持 | + +示例:下例中的 KCL schema Pet,包含两个预定义的属性 name 和 id,除此之外,还允许使用该 schema 的配置额外地赋值其他 key 为 string 类型,value 为 bool 类型的属性: + +```python +# KCL schema Pet,包含两个预定义的属性 name 和 id,允许额外给 key 为 string、value 为 bool 的属性赋值 +schema Pet: + name: str + id?: int + [...str]: bool + +# 对应的 OpenAPI 描述 +{ + "definitions": { + "Pet": { + "type": "object", + "properties": { + "name": { + "type": "string", + }, + "id": { + "type": "integer", + "format": "int64", + } + }, + "additionalProperties": { + "type": "bool" + }, + "required": [ + "name" + ], + } + }, + "swagger": "2.0", + "info": { + "title": "demo", + "version": "v1" + } +} +``` + +### schema 继承关系 + +### 内联 schema + +OpenAPI 支持嵌套地定义 schema,但 KCL 目前暂不支持 schema 的内联。OpenAPI 中内联定义的 schema 将被转换为 KCL 中带名称的 schema,其名称的命名规则为:在该内联 schema 的上层 schema 名称的基础上,增加相应的后缀。在拼接后缀时,根据定义了该内联 schema 的外层 OpenAPI 元素类型,后缀内容如下: + +| OpenAPI 文档中定义内联 schema 的元素 | KCL schema 名称拼接规则 | +| ------------------------------------ | ------------------------------ | +| 某属性节点 | 增加该属性节点的名称为后缀 | +| AdditionalProperties 节点 | 增加"AdditionalProperties"后缀 | + +注:KCL 未来也可能会支持内联 schema,届时再更新这部分转换规则 +示例 1:下例中的模型 Deployment 包含有 kind、spec 两个属性,其中 deploymentSpec 属性的 schema 通过内联的方式定义: + +```python +# OpenAPI 文档 +{ + "definitions": { + "Deployment": { + "type": "object", + "properties": { + "kind": { + "type": "string", + }, + "spec": { + "type": "object", + "properties": { + "replicas": { + "type": "integer", + "format": "int64" + } + } + } + }, + "required": [ + "kind", + "spec" + ], + } + }, + "swagger": "2.0", + "info": { + "title": "demo", + "version": "v1" + } +} + +# 转换为 KCL Schema 如下: +schema Deployment: + kind: str + spec: DeploymentSpec + +schema DeploymentSpec: + replicas?: int +``` + +示例 2:下例中的模型 Person 中除固定属性 name 外,还允许包含额外的属性(additionalProperties),并且这部分额外属性的属性值的 schema 通过内联的方式定义: + +```python +# OpenAPI 文档 +{ + "definitions": { + "Person": { + "type": "object", + "properties": { + "name": { + "type": "string", + }, + }, + "required": [ + "name", + "spec" + ], + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + } + }, + "swagger": "2.0", + "info": { + "title": "demo", + "version": "v1" + } +} + +# 转换为 KCL Schema 如下: +schema Person: + name: str + [...str]: [PersonAdditionalProperties] + +schema PersonAdditionalProperties: + name: str + description?: str +``` + +## KCL 文档 + +KCL doc 规范请参考:[传送门](../kcl/docgen.md) +KCL 文档包含 module 文档、schema 文档两类,其中 schema 文档可以由 OpenAPI 转换得到。KCL schema 文档包含: + +- schema 描述信息:位于 schema 声明之后、schema 属性声明之前,是对 schema 的总体介绍 +- schema 属性信息:位于 shcema 描述信息之后,以 Attributes + 分割线分隔 +- schema 附加信息:位于 schema 属性信息之后,以 See Also + 分割线分隔 +- schema 示例信息:位于 schema 附加信息之后,以 Examples + 分割线分隔 + +它们与 OpenAPI 规范的对应关系如下: + +| KCL 文档元素 | OpenAPI 元素 | +| --------------- | ---------------------------------------------------- | +| schema 描述信息 | definitions 节点下,每个模型节点的 description 字段 | +| schema 属性信息 | properties 节点下,每个属性节点的 description 字段 | +| schema 附加信息 | definitions 节点下,每个模型节点的 externalDocs 字段 | +| schema 示例信息 | definitions 节点下,每个模型节点的 example 字段 | + +示例: +下例中为 Pet 模型定义了其 schema 描述文档 "The schema Pet definition";Pet 的两个属性 "name" 和 "id" 也分别定义了其属性文档 "The name of the pet" 及 "The id of the pet";Pet 的附加信息为 "Find more info here. [https://petstore.swagger.io/](https://petstore.swagger.io/)";此外,Pet 模型还提供了模型实例的示例写法。 + +```python +# KCL schema Pet,采用规范的 KCL 文档格式 +schema Pet: + """The schema Pet definition + + Attributes + ---------- + name : str, default is Undefined, required + The name of the pet + id : int, default is -1, optional + The age of the pet + + See Also + -------- + Find more info here. https://petstore.swagger.io/ + + Examples + -------- + pet = Pet { + name = "doggie" + id = 123 + } + """ + name: str + id?: int = -1 + +# 对应的 OpenAPI 文档 +{ + "definitions": { + "Pet": { + "description": "The schema Pet definition", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the pet" + }, + "id": { + "type": "integer", + "format": "int64", + "default": -1, + "description": "The age of the pet" + } + }, + "required": [ + "name" + ], + "externalDocs": { + "description": "Find more info here", + "url": "https://petstore.swagger.io/" + }, + "example": { + "name": "doggie", + "id": 123 + } + } + }, + "swagger": "2.0", + "info": { + "title": "demo", + "version": "v1" + } +} +``` + +​ + +## 基本数据类型 + +| JSON Schema type | swagger type | KCL type | comment | +| ---------------- | --------------------------- | --------------- | --------------------------------------------------------------------------- | +| boolean | boolean | bool | | +| number | number | float | | +| | number format double | **unsupported** | | +| | number format float | float | | +| integer | integer | int (32) | | +| | integer format int64 | **unsupported** | | +| | integer format int32 | int (32) | | +| string | string | str | | +| | string format byte | str | | +| | string format int-or-string | int | str | +| | string format binay | str | | +| | string format date | unsupported | As defined by full-date - [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) | +| | string format date-time | unsupported | As defined by date-time - [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) | +| | string format password | unsupported | for swagger: A hint to UIs to obscure input. | +| | datetime | datetime | | + +## Reference + +- openapi spec 2.0:[https://swagger.io/specification/v2/](https://swagger.io/specification/v2/) +- openapi spec 3.0:[https://spec.openapis.org/oas/v3.1.0](https://spec.openapis.org/oas/v3.1.0) +- openapi spec 3.0(swagger 版本):[https://swagger.io/specification/](https://swagger.io/specification/) +- openapi spec 2.0 #SchemaObject:[https://swagger.io/specification/v2/#schemaObject](https://swagger.io/specification/v2/#schemaObject) +- go swagger:[https://goswagger.io/use/models/schemas.html](https://goswagger.io/use/models/schemas.html) +- swagger data models:[https://swagger.io/docs/specification/data-models/](https://swagger.io/docs/specification/data-models/) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/_category_.json new file mode 100644 index 000000000..d46abc771 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "包管理工具", + "position": 2 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/1.init.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/1.init.md new file mode 100644 index 000000000..f5d9290c4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/1.init.md @@ -0,0 +1,72 @@ +# kcl mod init + +初始化一个 kcl 包。 + +## 使用 + +```shell +kcl mod init [options][package_name] +``` + +## 介绍 + +`kcl mod init` 会在当前目录初始化一个 kcl 包。如果没有提供包名,会使用当前目录的名字作为包名。 + +如果提供了包名,会在当前目录下创建一个以包名命名的子目录,并在该目录下初始化 kcl 包。 + +`kcl mod init` 会在包目录下创建 `kcl.mod`、`kcl.mod.lock` 和 `main.k`。 + +## 选线 + +### --help, -h + +显示帮助信息。 + +## 示例 + +### 初始化当前目录为 kcl 包 + +```shell +# 创建一个目录 +mkdir my_package + +# 进入目录 +cd my_package + +# 初始化当前目录为 kcl 包 +kcl mod init +``` + +### 初始化一个名为 my_package 的 kcl 包 + +```shell +# 初始化一个名为 my_package 的 kcl 包 +kcl mod init my_package +``` + +## 命令参考 + +```shell +This command initializes new kcl module in current directory. + +Usage: + kcl mod init [flags] + +Examples: + kcl mod init [arguments]... + # Init one kcl module with the current folder name + kcl mod init + + # Init one kcl module with the name + kcl mod init package-name + + # Init one kcl module with the name and version + kcl mod init package-name --version 0.1.0 + +Flags: + -h, --help help for init + --version string init module version + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/10.help.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/10.help.md new file mode 100644 index 000000000..7c6fb240a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/10.help.md @@ -0,0 +1,21 @@ +# kcl mod help + +输出 kcl mod 命令的帮助信息。 + +## 使用 + +```shell +kcl mod help +``` + +## 介绍 + +`kcl mod help` 会输出 kcl mod 命令的帮助信息。 + +## 示例 + +使用 `kcl mod help` 输出 kcl mod 命令的帮助信息。 + +```shell +kcl mod help +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/11.update.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/11.update.md new file mode 100644 index 000000000..fdc76687b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/11.update.md @@ -0,0 +1,46 @@ +# kcl mod update + +kcl mod update 将根据 kcl.mod 更新在 kcl.mod.lock 中列出的依赖项。也可以通过指定包的路径来更新一个包。 + +## 使用 + +```shell +kcl mod update [options][module_name] +``` + +## 示例 + +### 更新当前模块 + +```shell +kcl mod update +``` + +### 更新指定路径的模块 + +```shell +kcl mod update path/to/package +``` + +## 命令参数 + +```shell +This command updates dependencies listed in kcl.mod.lock based on kcl.mod. + +Usage: + kcl mod update [flags] + +Examples: + # Update the current module + kcl mod update + + # Update the module with the specified path + kcl mod update path/to/package + +Flags: + -h, --help help for update + --no_sum_check do not check the checksum of the package and update kcl.mod.lock + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/12.graph.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/12.graph.md new file mode 100644 index 000000000..9aabd2178 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/12.graph.md @@ -0,0 +1,37 @@ +# kcl mod graph + +打印模块依赖关系图。每个模块都以 `path@version` 的形式标识进行输出 + +## 使用 + +```shell +kcl mod graph [flags] +``` + +## 示例 + +### 打印当前模块的依赖关系图 + +```shell +kcl mod graph +``` + +## 命令参数 + +```shell +This command prints the module dependency graph. +Each module is identified as a string of the form path@version. + +Usage: + kcl mod graph [flags] + +Examples: + # Print the current module dependency graph. + kcl mod graph + +Flags: + -h, --help help for graph + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/2.add.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/2.add.md new file mode 100644 index 000000000..bef2702a0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/2.add.md @@ -0,0 +1,97 @@ +# kcl mod add + +添加一个依赖到 kcl 包。 + +## 使用 + +```shell +kcl mod add [options][package_reference] +``` + +## 介绍 + +`kcl mod add` 会添加一个依赖到 kcl 包。依赖可以来自 git 仓库,或者 kcl registry。 + +`package_reference` 是一个 kcl 包引用,格式为 `package_name:version`。 + +## 选项 + +### --git + +指定依赖来自 git 仓库的 git url。 + +### --tag + +指定依赖来自 git 仓库的 tag。 + +### --help, -h + +显示帮助信息。 + +## 示例 + +### 添加一个来自 kcl registry 的依赖 + +添加一个名为 `k8s` 的依赖,版本为最新版本。 + +```shell +kcl mod add k8s +``` + +添加一个名为 `k8s` 的依赖,版本为 `v1.27.2`。 + +```shell +kcl mod add k8s:1.29 +``` + +### 添加一个来自 git 仓库的依赖 + +添加一个来自 git 仓库的 kcl 包依赖,tag 为 v0.1.0 + +```shell +kcl mod add --git https://github.com/awesome-kusion/konfig.git --tag v0.1.0 +``` + +## 命令参考 + +```shell +This command adds new dependency + +Usage: + kcl mod add [flags] + +Examples: + # Add the module dependency named "k8s" + kcl mod add k8s + + # Add the module dependency named "k8s" with the version "1.28" + kcl mod add k8s:1.28 + + # Add the module dependency from the GitHub by git url + kcl mod add git://github.com/kcl-lang/konfig --tag v0.4.0 + + # Add the module dependency from the OCI Registry by oci url + kcl mod add oci://ghcr.io/kcl-lang/helloworld --tag 0.1.0 + + # Add the module dependency from the local file system by file url + kcl mod add /path/to/another_module + + # Add the module dependency from the GitHub by flag + kcl mod add --git https://github.com/kcl-lang/konfig --tag v0.4.0 + + # Add the module dependency from the OCI Registry by flag + kcl mod add --oci https://ghcr.io/kcl-lang/helloworld --tag 0.1.0 + +Flags: + --branch string git repository branch + --commit string git repository commit + --git string git repository url + -h, --help help for add + --no_sum_check do not check the checksum of the package and update kcl.mod.lock + --oci string oci repository url + --rename string rename the dependency + --tag string git or oci repository tag + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/3.pkg.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/3.pkg.md new file mode 100644 index 000000000..c11a06700 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/3.pkg.md @@ -0,0 +1,60 @@ +# kcl mod pkg + +打包一个 kcl 包。 + +## 使用 + +```shell +kcl mod pkg [options] +``` + +## 介绍 + +`kcl mod pkg` 会打包一个 kcl 包为 `*.tar`。 + +选项 `--target` 用于指定打包后的 `*.tar` 文件路径。 + +## 选项 + +### --target + +指定打包后的 `*.tar` 文件路径。 + +### --help, -h + +显示帮助信息。 + +## 示例 + +### 打包当前 kcl 包为 `*.tar` + +```shell +kcl mod pkg --target /Users/my_package_tar +``` + +## 命令参数 + +```shell +This command converts a kcl module into tar + +Usage: + kcl mod pkg [flags] + +Examples: + # Package the current module + kcl mod pkg + + # Package the current module in the vendor mode + kcl mod pkg --vendor + + # Package the current module into the target directory + kcl mod pkg --target /path/to/target_dir + +Flags: + -h, --help help for pkg + --target string packaged target path + --vendor package in vendor mode (default: false) + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/4.metadata.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/4.metadata.md new file mode 100644 index 000000000..a0ad85d62 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/4.metadata.md @@ -0,0 +1,68 @@ +# kcl mod metadata + +打印 kcl 包的元数据。 + +## 使用 + +```shell +kcl mod metadata [options] +``` + +## 介绍 + +`kcl mod metadata` 会打印 kcl 包的元数据。元数据包括包的依赖信息。 + +`--update` 选项用于自动下载缺失的依赖包。 + +## 选项 + +### --update + +自动下载缺失的依赖包。 + +### --help, -h + +展示 `kcl mod metadata` 命令的帮助信息。 + +## 示例 + +### 打印 kcl 包的元数据 + +打印 kcl 包的元数据。 + +```shell +kcl mod metadata +``` + +打印 kcl 包的元数据,并自动下载缺失的依赖包。 + +```shell +kcl mod metadata --update +``` + +## 命令参数 + +```shell +This command outputs the resolved dependencies of a package + +Usage: + kcl mod metadata [flags] + +Examples: + # Output the resolved dependencies the current module + kcl mod metadata + + # Output the resolved dependencies the current module in the vendor mode + kcl mod metadata --vendor + + # Output the resolved dependencies the current module with the update check + kcl mod metadata --update + +Flags: + -h, --help help for metadata + --update check the local package and update and download the local package. (default: false) + --vendor run in vendor mode (default: false) + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/6.login.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/6.login.md new file mode 100644 index 000000000..0bf1677ad --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/6.login.md @@ -0,0 +1,96 @@ +# kcl registry login + +登陆 kcl registry. + +## 使用 + +```shell +kcl registry login [options][kpm_registry] +``` + +## 介绍 + +`kcl registry login` 将会登陆 kcl registry。 + +## 选项 + +### --username, -u + +指定 kcl registry 的用户名。 + +### --password, -p + +指定 kcl registry 的密码。 + +### --help, -h + +展示 `kcl registry login` 命令的帮助信息。 + +## 示例 + +### 登陆到 kcl registry, 通过参数输入用户名和密码 + +```shell +kcl registry login -u -p +``` + +期望输出为 + +```shell +Login succeeded +``` + +### 登陆到 kcl registry, 通过参数输入用户名,密码通过交互式输入 + +```shell +kcl registry login -u +``` + +期望输出为 + +```shell +Password: +Login succeeded +``` + +### 登陆到 kcl registry, 用户名和密码通过交互式输入 + +```shell +kcl registry login +``` + +期望输出为 + +```shell +Username: +Password: +Login succeeded +``` + +## 命令参数 + +```shell +This command can be used to login to a registry. + +Usage: + kcl registry login [flags] + +Examples: + # Login the docker hub + kcl registry login docker.io + + # Login the GitHub container registry + kcl registry login ghcr.io + + # Login a localhost registry + kcl registry login https://localhost:5001 + + +Flags: + -h, --help help for login + -p, --password string registry password or identity token + -u, --username string registry username + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/7.logout.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/7.logout.md new file mode 100644 index 000000000..01c9efebc --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/7.logout.md @@ -0,0 +1,47 @@ +# kcl registry logout + +从 kcl registry 登出。 + +## 使用 + +```shell +kcl registry logout [options][kpm_registry] +``` + +## 介绍 + +`kcl registry logout` 会从 registry 登出。 + +## 选项 + +### --help, -h + +展示 `kcl registry logout` 命令的帮助信息。 + +## 示例 + +### 从 kcl registry 登出 + +```shell +kcl registry logout +``` + +## 命令参数 + +```shell +This command can be used to logout from the current registry. + +Usage: + kcl registry logout [flags] + +Examples: + # Logout the registry + kcl registry logout docker.io + + +Flags: + -h, --help help for logout + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/8.push.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/8.push.md new file mode 100644 index 000000000..baa54eff8 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/8.push.md @@ -0,0 +1,70 @@ +# kcl mod push + +上传一个 kcl 包到 kcl mod registry。 + +## 使用 + +```shell +kcl mod push [options][kpm_registry] +``` + +## 介绍 + +`kcl mod push` 将会上传一个 kcl 包到 kcl mod registry。 + +## 选项 + +### --tar_path + +指定上传的 `*.tar` 文件路径。 + +### --help, -h + +展示 `kcl mod push` 命令的帮助信息。 + +## 示例 + +### 上传当前 kcl 包到 kcl mod registry + +你可以在 kcl 包的根目录下使用 `kcl mod push` 命令上传一个 kcl 包到 kcl mod registry。 + +```shell +# 创建一个 kcl 包 +kcl mod init +# 进入 kcl 包目录 +cd +# 上传 kcl 包到 kcl mod registry +kcl mod push +``` + +### 上传一个 `*.tar` 文件到 kcl mod registry + +你也可以使用 `kcl mod push` 命令上传一个 `*.tar` 文件到 kcl mod registry。 + +```shell +kcl mod push --tar_path +``` + +## 命令参数 + +```shell +This command pushes kcl modules to the registry. + +Usage: + kcl mod push [flags] + +Examples: + # Push the current module to the registry + kcl mod push + + # Push the current module to the registry in the vendor mode + kcl mod push --vendor + +Flags: + -h, --help help for push + --tar_path string packaged target path that will be pushed + --vendor run in vendor mode (default: false) + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/9.pull.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/9.pull.md new file mode 100644 index 000000000..c0b049b7f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/9.pull.md @@ -0,0 +1,80 @@ +# kcl mod pull + +下载 kcl 包从 kcl mod registry。 + +## 使用 + +```shell +kcl mod pull [options][package_source] +``` + +## 介绍 + +`kcl mod pull` 会从 kcl mod registry 下载 kcl 包。 + +## 选项 + +### --tag + +使用 oci url 下载包时, 指定要下载的 kcl 包的 tag。 + +### --help, -h + +展示 `kcl mod pull` 命令的帮助信息。 + +## 示例 + +### 从 kcl mod registry 下载 kcl 包 + +你可以使用 `kcl mod pull` 命令从 默认的 kcl mod registry 下载 kcl 包。 + +```shell +kcl mod pull : +``` + +### 下载 kcl 包通过 oci url + +你可以使用 `kcl mod pull` 命令从一个 oci url 下载 kcl 包。 + +```shell +kcl mod pull --tag +``` + +## 命令参数 + +```shell +This command pulls kcl modules from the registry. + +Usage: + kcl mod pull [flags] + +Examples: + # Pull the the module named "k8s" to the local path from the registry + kcl mod pull k8s + + # Pull the module dependency named "k8s" with the version "1.28" + kcl mod pull k8s:1.28 + + # Pull the module from the GitHub by git url + kcl mod pull git://github.com/kcl-lang/konfig --tag v0.4.0 + + # Pull the module from the OCI Registry by oci url + kcl mod pull oci://ghcr.io/kcl-lang/helloworld --tag 0.1.0 + + # Pull the module from the GitHub by flag + kcl mod pull --git https://github.com/kcl-lang/konfig --tag v0.4.0 + + # Pull the module from the OCI Registry by flag + kcl mod pull --oci https://ghcr.io/kcl-lang/helloworld --tag 0.1.0 + +Flags: + --branch string git repository branch + --commit string git repository commit + --git string git repository url + -h, --help help for pull + --oci string oci repository url + --tag string git or oci repository tag + +Global Flags: + -q, --quiet Set the quiet mode (no output) +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/_category_.json new file mode 100644 index 000000000..abcc956a0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/tools/cli/package-management/command-reference/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "命令参考", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/_category_.json new file mode 100644 index 000000000..d3ae7a0a5 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "核心概念", + "position": 5 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/concepts.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/concepts.md new file mode 100644 index 000000000..423b94a44 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/concepts.md @@ -0,0 +1,7 @@ +# 核心概念 + +学习更多关于 KCL 核心概念。 + +import DocCardList from '@theme/DocCardList'; + + diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/package-and-module.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/package-and-module.md new file mode 100644 index 000000000..4c8669fcd --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/package-and-module.md @@ -0,0 +1,156 @@ +# 模块和包 + +本节主要介绍如何组织 KCL 中的文件。 + +## 概述 + +在一个**module**中,KCL 按**package**进行组织文件。package 可以在 module 内定义,也可以通过 KCL 包管理器 `kpm` 从外部导入。在后一种情况下,KCL 在专用位置中维护包的副本。 + +## Module + +KCL 模块按目录层次结构布置配置。它包含了确定 KCL 配置结果所需的一切。此目录的根标记为包含 `kcl.mod` 目录。此目录的内容大多由 kcl 工具(如 `kpm` 等)管理。从这个意义上讲,`kcl.mod` 类似于 `.git` 目录,标记着仓库的根目录,但它的内容主要由 git 工具管理。此外,KCL 模块是文件组织的最大单位,具有所有 KCL 文件和依赖项的固定位置。 + +> 注意: 使用 KCL 模块(例如 `kcl.mod`)是可选的,但如果您想使用语义版本管理、分发、共享和重用代码,则需要使用它。 + +### 创建一个 module + +可以通过在模块根目录中运行以下命令来创建模块: + +```bash +kcl mod init [module name] +``` + +模块名在需要在模块内导入另一个模块的包时是**必需的**。也可以通过手动设置 `kcl.mod` 文件来创建模块。 + +## Package + +在 KCL 中,一个包通常由包含 KCL 文件的“文件夹”组成。这个文件夹可以是实际的磁盘物理路径,也可以由多个 KCL 文件(通常是主包)组成。不同的包通过不同的包路径(如 `kubernetes.core.v1`)唯一地定位。 + +在同一个模块内,可以通过相对或绝对路径的 import 语句互相导入不同的包。在 KCL 解析过程中,相对 import 将被替换为绝对 import,并通过包路径找到相应的 KCL 代码。 + +### 相对导入路径 + +我们可以使用 `.` 运算符来实现 KCL 入口文件的相对路径导入。 + +main.k: + +```python +import .model1 # Current directory module +import ..service # Parent directory +import ...root # Parent of parent directory + +s = service.ImageService {} +m = root.Schema {} +``` + +### 绝对导入路径 + +KCL 语句`import a.b.c.d` 的语义是: + +1. 如果 `kcl.mod` 不存在,则将当前目录视为包根目录,并从当前目录搜索路径 `a/b/c/d`。 +2. 如果当前目录搜索失败,则从根路径 `ROOT_PATH/a/b/c/d` 搜索,否则引发导入错误。 + +根路径 `ROOT_PATH` 的定义是相对于 `kcl.mod` 文件的目录。 + +代码结构: + +```bash +. +└── root + ├── kcl.mod + ├── model + │ ├── model1.k + | ├── model2.k + │ └── main.k + ├── service + │ └── service1.k + └── mixin + └── mixin1.k +``` + +### 内置包 + +KCL 有一系列内置包,例如 `math`,`regex` 等。要使用内置包,直接导入并使用其限定标识符调用函数。例如, + +```python +import regex + +image = "nginx:1.14.2" +is_match = regex.match(image, "^[a-zA-Z]+:\d+\.\d+\.\d+$") + +``` + +输出的 YAML 为 + +```yaml +image: nginx:1.14.2 +is_match: true +``` + +### 插件包 + + + +KCL 还有一系列插件包,例如 `hello`,`project_context` 等。要使用插件包,需要用 `kcl_plugin.` 包路径前缀导入,并使用其限定标识符调用函数。例如, + +```python +import kcl_plugin.hello + +result = hello.add(1, 1) +``` + +输出的 YAML 为 + +```yaml +result: 2 +``` + +### 主包 + +在 KCL 中,主包的组成通常由编译器参数确定。这是因为KCL模式和约束可以在包中的文件中分隔,甚至可以在目录中组织,考虑将配置写入和维护在隔离块中的便利性。 + +#### 属于主包的文件 + +用户可以使用KCL命令行决定使用哪些配置和约束,例如, + +```bash +kcl file1.k file2.k +``` + +因此,主包包含两个名为 `file1.k` 和 `file2.k` 的 KCL 文件。 + +如果 KCL 被告知为特定目录加载文件,例如: + +```bash +kcl ./path/to/package +``` + +它将只查找 `.k` 后缀的 KCL 文件,并忽略 `_` 或 `_test.k` 前缀的 KCL 文件合并到主包中。此外,如果 `./path/to/package` 包含 `kcl.yaml` 文件,则 `kcl.yaml` 文件将被忽略。 + +此外,我们可以通过配置命令行编译设置文件(例如 `kcl.yaml`)来设置主包文件,如下所示: + +```yaml +kcl_cli_configs: + files: + - file1.k + - file2.k +``` + +```bash +kcl -Y kcl.yaml +``` + +> 注意:如果没有为 KCL 指定任何输入文件,KCL 将从命令行执行路径查找默认的 `kcl.yaml` 文件读取输入文件。此外,如果我们告诉KCL输入文件和编译设置文件,KCL将把用户输入的输入文件作为最终值。 + +```bash +# 无论`kcl.yaml` 中是否配置 `files` 字段,输入文件的最终值为["file1.k", "file2.k"] +kcl -Y kcl.yaml file1.k file2.k +``` + +## kcl.mod 和 kcl.yaml 异同 + +首先,在 KCL 中,`kcl.mod` 和 `kcl.yaml` 都是可选的。它们之间的区别在于 `kcl.mod` 确定包路径的根路径以及 KCL 模块是否具有分发和重用要求,而 `kcl.yaml` 确定主包的 KCL 文件组成。 + +其次,对于仅用于外部使用的 kcl module,`kcl.yaml` 是可选的,但 `kcl.mod` 是必需的,因为 `kcl.mod` 需要声明 KCL 版本,模块版本,依赖关系和其他信息。 + +最后,对于 KCL IDE 插件,它需要知道主包信息才能形成完整的编译过程,因此它需要根据光标位置自动查找主包组成,因为没有人可以通过 KCL 命令行指定这些信息。一般的查询逻辑是查找 `kcl.yaml` 的存在性。如果找到了,主包由 `kcl.yaml` 中的文件属性组成,如果找不到,主包由当前文件组成。KCL IDE 插件会有选择地了解 `kcl.mod` 文件。当 `kcl.mod` 文件存在时,IDE 插件会读取所有包路径及其在外部依赖项中的实际路径的相应信息。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/type-and-definition.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/type-and-definition.md new file mode 100644 index 000000000..07b5bc888 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/concepts/type-and-definition.md @@ -0,0 +1,94 @@ +# 类型和定义 + +This section mainly covers the concepts related to types and definitions. + +## 类型 + +KCL features a **gradual static type system**, initially designed to consider scalability. Its aim is to significantly reduce the configuration writing difficulties for users while maintaining stability. Static typing enhances code quality, acts as documentation, and helps detect errors at an early stage when needed. For instance, defining a complete static type for data like JSON/YAML can be challenging, similar to how TypeScript adds complexity in handling type gymnastics due to the lack of runtime type checks for Javascript. In contrast, KCL incorporates a similar TypeScript type system while still retaining runtime type checks. Thus, type errors will always appear at runtime. Consequently, KCL has types, but they can be selectively used when necessary, and it handles interactions between typed and untyped code elegantly and securely. + +The configuration of attributes and types in KCL usually follows a simple pattern: + +$$ +k\ o \ (T) \ v +$$ + +where $k$ is the attribute name, $v$ is the attributes value, and $T$ is the type annotation. Since KCL has the ability of the type inference, $T$ is usually omitted. + +By default, KCL does not require type annotations and performs type checks at runtime. + +```python +name = "nginx" # The type of `name` is `str` +port = 80 # The type of `port` is `int` +``` + +As long as we operate on basic types such as integers and strings, it is generally sufficient to annotate the default type and directly write the configuration. KCL can infer the type of basic data. We recommend writing types for complex structures and function definitions, which will clearly provide a good input prompt for other users who use structures and functions. + +```python +# Types for schema +schema App: + name: str + domainType: "Standard" | "Customized" | "Global" + containerPort: int + volumes: [Volume] + services: [Service] + + check: + 1 <= containerPort <= 65535 + +schema Service: + clusterIP: str + $type: str + + check: + clusterIP == "None" if $type == "ClusterIP" + +schema Volume: + container: str = "*" # The default value of `container` is "*" + mountPath: str + + check: + mountPath not in ["/", "/boot", "/home", "dev", "/etc", "/root"] + +# Types for lambda +appFilterFunc = lambda apps: [App], name: str -> [App] { + [a for a in apps if a.name == name] +} +``` + +More formal definitions and usage of types are at the [type specification document](/docs/reference/lang/types/) and the [tour document of the type system](/docs/reference/lang/tour#type-system) + +**Schema** is the core type in KCL, just like a database schema, which defines the organization of configuration data. This includes logical constraints such as schema names, fields, data types, and the relationships between these entities. Patterns typically use visual representations to convey the architecture of a database, becoming the foundation for organizing configuration data. The process of designing schema patterns is also known as configuration modeling. KCL Schema typically serves various roles, such as application developers, DevOps platform administrators, and SRE, and provides them with a unified configuration interaction interface. + +In addition, the ability to enforce constraints from top to bottom is crucial for any large-scale configuration setting. Therefore, KCL not only provides the ability to define static types but also provides the rich ability to define constraints, which is to some extent equivalent to assertion statements in programming languages. To prevent assertions from constantly expanding, we place structural constraints together with structural type definitions and support custom error messages. + +In KCL, we can use schema to organize the configuration data to meet the requirements of model definition, abstraction, and templating. Schema is the core feature of KCL, which defines attributes, operations, and check-blocks. Usually, a formal form of KCL Schema can be written in the following form: + +$$ +S = \Sigma_{i = 1}^{N} \{s_i, T_i, \mathcal{T}[s_i]\}, +$$ + +where $N$ is the total number of attributes, $\mathcal{T}$ is the attribute constraint, $s_i$ and $T_i$ denotes the $i$-th attribute name and type. Simultaneously, to improve the reusability of the code and meet the needs of hierarchical definition, KCL draws on the experience of OOP and uses single inheritance to reuse and extend the schema. Schema inheritance can be regarded as a special type of partial order relationship, and satisfies + +$$ +unionof(T_1, T_2) = T_2 \Leftrightarrow T_1 \subseteq T_2, +$$ + +where $T_1$ and $T_2$ are both schema types. When the above equation is not satisfied, the KCL will throw a type check error. + +A typical schema with constraints is defined as follows: + +```python +import regex + +schema Secret: + name: str + # Data defines the keys and data that will be used by secret. + data?: {str:str} + + check: + all k in data { + regex.match(k, r"[A-Za-z0-9_.-]*") + } if data, "a valid secret data key must consist of alphanumeric characters, '-', '_' or '.'" +``` + +More specifications and usage of KCL schema and constraint is [here](/docs/reference/lang/spec/schema). diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/_category_.json new file mode 100644 index 000000000..c826d665d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "快速开始", + "position": 1 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/index.md new file mode 100644 index 000000000..509f2cea6 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/index.md @@ -0,0 +1,5 @@ +# 快速开始 + +import DocCardList from '@theme/DocCardList'; + + diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/install.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/install.md new file mode 100644 index 000000000..9ac191b5f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/install.md @@ -0,0 +1,219 @@ +--- +sidebar_position: 2 +--- + +# 安装 + +## 1. 安装 KCL + +### 二进制下载 + +KCL 的每个版本都包含各种操作系统和体系结构。这些二进制版本可以从 [Github](https://github.com/kcl-lang/cli/releases/) 手动下载并安装,下载完成后将 `{install-location}/kclvm/bin` 添加到环境变量 PATH 中。 + +#### MacOS & Linux + +```bash +export PATH=$PATH:{install-location} +``` + +#### Windows + +```powershell +$env:PATH += ";{install-location};" +``` + +### 使用脚本安装最新版本 + +#### MacOS + +将 KCL darwin 最新版本安装到 /usr/local/bin + +```bash +curl -fsSL https://kcl-lang.io/script/install-cli.sh | /bin/bash +``` + +卸载 + +```bash +curl -fsSL https://kcl-lang.io/script/uninstall-cli.sh | /bin/bash +``` + +#### Linux + +将 KCL linux 最新版本安装到 /usr/local/bin + +```bash +wget -q https://kcl-lang.io/script/install-cli.sh -O - | /bin/bash +``` + +卸载 + +```bash +wget -q https://kcl-lang.io/script/uninstall-cli.sh -O - | /bin/bash +``` + +#### Windows + +将 KCL windows 最新版本安装到 $Env:SystemDrive\kclvm\bin,并将该目录添加到用户 PATH 环境变量中。 + +```bash +powershell -Command "iwr -useb https://www.kcl-lang.io/script/install-cli.ps1 | iex" +``` + +卸载 + +```shell +powershell -Command "iwr -useb https://www.kcl-lang.io/script/uninstall-cli.ps1 | iex" +``` + +#### Homebrew (MacOS) + +- 安装最新版本 + +```bash +# 安装最新版本 +brew install kcl-lang/tap/kcl@0.8.0 + +# 安装固定版本 +brew install kcl-lang/tap/kcl@x.y.z +``` + +- 升级 + +```bash +brew upgrade kcl-lang/tap/kcl +``` + +- 卸载 + +```bash +brew uninstall kcl-lang/tap/kcl +``` + +#### Scoop (Windows) + +首先安装 [Scoop](https://scoop.sh/), 然后通过如下命令安装 `kcl`: + +```bash +scoop bucket add kcl-lang https://github.com/kcl-lang/scoop-bucket.git +scoop install kcl-lang/kcl +``` + +### 使用 Go 安装 + +通过 `Go` 命令安装 (Go 要求 1.22+) + +```bash +go install kcl-lang.io/cli/cmd/kcl@latest +``` + +### 使用 Docker 镜像安装 + +- 基本命令 + +```bash +docker run --rm -it kcllang/kcl +``` + +- 更新镜像 + +```bash +docker pull kcllang/kcl +``` + +### 使用 Nix 安装 + +查看[这里](https://search.nixos.org/packages?channel=unstable&show=kcl&from=0&size=50&sort=relevance&type=packages&query=kcl) + +### 注意 + +可以执行运行如下命令确保 KCL 已经正确安装 + +```bash +kcl --help +``` + +如果您无法成功安装并运行 KCL,可以参考[这里](/docs/user_docs/support/faq-install) + +## 2. 安装 KCL IDE 插件 + +### 安装语言服务器 + +在我们启用 IDE 插件之前,首先我们安装 KCL Language Server 二进制并添加到 PATH 中。 + +#### MacOS + +将 KCL language server darwin 最新版本安装到 /usr/local/bin + +```bash +curl -fsSL https://kcl-lang.io/script/install-kcl-lsp.sh | /bin/bash +``` + +#### Linux + +将 KCL language server linux 最新版本安装到 /usr/local/bin + +```bash +wget -q https://kcl-lang.io/script/install-kcl-lsp.sh -O - | /bin/bash +``` + +#### Windows + +将 KCL language server windows 最新版本安装到 $Env:SystemDrive\kclvm\bin,并将该目录添加到用户 PATH 环境变量中。 + +```bash +powershell -Command "iwr -useb https://www.kcl-lang.io/script/install-kcl-lsp.ps1 | iex" +``` + +### Homebrew (MacOS) + +- 安装最新版本 + +```bash +# 安装最新版本 +brew install kcl-lang/tap/kcl-lsp@0.7.0 + +# 安装固定版本 +brew install kcl-lang/tap/kcl-lsp@x.y.z +``` + +- 升级 + +```bash +brew upgrade kcl-lang/tap/kcl-lsp +``` + +- 卸载 + +```bash +brew uninstall kcl-lang/tap/kcl-lsp +``` + +### Scoop (Windows) + +首先安装 [Scoop](https://scoop.sh/), 然后通过如下命令安装 `kcl-language-server` 二进制: + +```bash +scoop bucket add kcl-lang https://github.com/kcl-lang/scoop-bucket.git +scoop install kcl-lang/kcl-lsp +``` + +### 安装 IDE 插件客户端 + +#### VS Code + +KCL 为 VS Code 本地版本提供了插件支持,并提供了高亮、自动补全、跳转、悬停、大纲等功能。您可以[点击这里](/docs/tools/Ide/vs-code)进行安装。 + +![Completion](/img/docs/tools/Ide/vs-code/Completion.gif) + +#### NeoVim + +参见[此处](https://github.com/kcl-lang/kcl.nvim)配置 KCL 语言服务器并启用它。 + +![kcl.nvim](/img/docs/tools/Ide/neovim/overview.png) + +#### IntelliJ IDEA + +KCL 为 IntelliJ IDEA 提供了插件支持。您可以[点击这里](/docs/tools/Ide/intellij)了解更多。 + +![intellij](/img/docs/tools/Ide/intellij/overview.png) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/intro.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/intro.md new file mode 100644 index 000000000..c359bf327 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/intro.md @@ -0,0 +1,216 @@ +--- +sidebar_position: 1 +--- + +# 简介 + +## KCL 是什么? + +[KCL](https://github.com/kcl-lang/kcl) 是一个开源的基于约束的记录及函数语言,作为沙盒项目托管在 CNCF 基金会。KCL 通过成熟的编程语言技术和实践来改进对大量繁杂配置比如云原生 Kubernetes 配置场景的编写,致力于构建围绕配置的更好的模块化、扩展性和稳定性,更简单的逻辑编写,以及更简单的自动化和生态工具集成。 + +## 为什么使用 KCL? + +KCL 期望通过更现代化的声明式配置语言和工具,在轻量级客户端云原生动态配置领域填补配置语言及工具的空白并解决如下问题: + +- **维度爆炸**: 大多数静态配置如云原生领域的 Kubernetes YAML 配置需要为每个环境单独进行配置;在最糟糕的情况下,它可能引入涉及环境交叉链接的难以调试的错误,稳定性和扩展性都较差。 +- **配置漂移**: 对于不同环境的静态管理应用程序和基础设施配置的方式,往往没有标准的方式去管理这些动态的不同环境的配置,采用非标准化的方法比如脚本和胶水代码的拼盘,会导致复杂度呈指数增长,并导致配置漂移。 +- **认知负担**: Kubernetes 等作为构建平台的平台技术手段在底层统一基础架构细节方面出色,但是缺乏更上层的应用软件交付抽象,对于普通开发者认知负担较高,影响了更上层应用开发者的软件交付体验。 + +针对如上问题,KCL 期望提供如下能力: + +- 通过**代码抽象**等手段屏蔽基础设施和平台的细节和复杂性,降低研发者**认知负担** +- **编辑**和**校验**已有的存量配置或模版,直接解决云原生小配置场景问题如 Helm Chart 配置硬编码问题,但远不止如此 +- 通过配置语言无副作用地**管理跨团队的大规模配置数据**,提升团队协作效率 + +具体来说,KCL 可以 + +- 在代码层面提升**配置语义验证**的能力,比如 Schema 定义、字段可选/必选、类型、范围等配置检查校验能力 +- 提供**配置分块编写、组合和抽象**的能力,比如结构定义、结构继承、约束定义和配置策略合并等能力 +- 用**现代编程语言**的方式以**编写代码**的方式提升配置的灵活度,比如条件语句、循环、函数、包管理等特性提升配置重用的能力 +- 提供**完备的工具链支持**,丰富的 IDE 插件、语言和生态工具链支持用以降低上手门槛,提升使用体验 +- 通过**包管理工具** 和 **OCI 注册表**使得配置以更简单的方式在不同团队/角色之间分享,传播和交付 +- 提供**高性能**的编译器满足规模化配置场景诉求,比如满足由一份基线配置根据部署上下文生成不同环境不同拓扑的配置的渲染性能以及配置自动化修改性能诉求 +- 通过**多语言 SDK,KCL 语言插件**等手段提升其**自动化集成**能力,在发挥配置及策略编写价值的同时显著降低 KCL 的学习成本 + +![](/img/docs/user_docs/intro/kcl-overview.png) + +除了语言自身,KCL 还提供了许多额外的工具如格式化,测试、文档、包管理等工具帮助您使用、理解和检查编写的配置或策略;通过 VS Code 等 IDE 插件和 Playground 降低配置编写、分享的成本;通过 Rust, Go, 和 Python 多语言 SDK 自动化地管理和执行配置。 + +KCL 本身提供了与其他语言、格式和云原生工具的许多集成。例如,我们可以使用 KCL 验证工具来验证terraform plan 文件, JSON/YAML 等格式,并使用导入工具从 terraform provider schema 和Kubernetes CRD 等直接生成 KCL Schema。此外得益于统一 [KRM KCL 规范](https://github.com/kcl-lang/krm-kcl),KCL 提供了几乎所有您所知道的云原生工具的集成。 + +KCL 是一种现代高级领域编程语言,并且它是一种编译静态的强类型语言。KCL 为开发人员提供了通过记录和函数语言设计将**配置(config)**、**建模抽象(schema)**、**逻辑(lambda)**和**策略(rule)**作为核心能力。 + +![](/img/docs/user_docs/intro/kcl-concepts.png) + +KCL 试图提供独立于运行时的可编程性,不在本地提供线程和 IO 等系统功能,并试图为解决领域问题并提供稳定、安全、低噪声、低副作用、易于自动化和易于管理的编程支持。通过不可变性、纯函数和属性运算符等语言特性,您可以在配置可扩展性和安全性方面获得一个良好的平衡。 + +总之,KCL 具备如下特点: + +- **简单易用**:源于 Python、Golang 等高级语言,采纳函数式编程语言特性,低副作用 +- **设计良好**:独立的 Spec 驱动的语法、语义、运行时和系统库设计 +- **快速建模**:以 [Schema](https://kcl-lang.io/docs/reference/lang/tour#schema) 为中心的配置类型及模块化抽象 +- **功能完备**:基于 [Config](https://kcl-lang.io/docs/reference/lang/tour#config-operations)、[Schema](https://kcl-lang.io/docs/reference/lang/tour#schema)、[Lambda](https://kcl-lang.io/docs/reference/lang/tour#function)、[Rule](https://kcl-lang.io/docs/reference/lang/tour#rule) 的配置及其模型、逻辑和策略编写 +- **可靠稳定**:依赖[静态类型系统](https://kcl-lang.io/docs/reference/lang/tour/#type-system)、[约束](https://kcl-lang.io/docs/reference/lang/tour/#validation)和[自定义规则](https://kcl-lang.io/docs/reference/lang/tour#rule)的配置稳定性 +- **强可扩展**:通过独立配置块[自动合并机制](https://kcl-lang.io/docs/reference/lang/tour/#-operators-1)保证配置编写的高可扩展性 +- **易自动化**:[CRUD APIs](https://kcl-lang.io/docs/reference/lang/tour/#kcl-cli-variable-override),[多语言 SDK](https://kcl-lang.io/docs/reference/xlang-api/overview),[语言插件](https://github.com/kcl-lang/kcl-plugin) 构成的梯度自动化方案 +- **极致性能**:使用 Rust & C,[LLVM](https://llvm.org/) 实现,支持编译到本地代码和 [WASM](https://webassembly.org/) 的高性能编译时和运行时 +- **API 亲和**:原生支持 [OpenAPI](https://github.com/kcl-lang/kcl-openapi)、 Kubernetes CRD, Kubernetes YAML 等 API 生态规范 +- **开发友好**:[语言工具](https://kcl-lang.io/docs/tools/cli/kcl/) (Format,Lint,Test,Vet,Doc 等)、 [IDE 插件](https://github.com/kcl-lang/vscode-kcl) 构建良好的研发体验 +- **安全可控**:面向领域,不原生提供线程、IO 等系统级功能,低噪音,低安全风险,易维护,易治理 +- **多语言 SDK**:[Rust](https://kcl-lang.github.io/docs/reference/xlang-api/rust-api), [Go](https://kcl-lang.github.io/docs/reference/xlang-api/go-api), [Python](https://kcl-lang.github.io/docs/reference/xlang-api/python-api), [Java](https://kcl-lang.github.io/docs/reference/xlang-api/java-api), [.NET](https://kcl-lang.github.io/docs/reference/xlang-api/dotnet-api), [Node.js](https://kcl-lang.github.io/docs/reference/xlang-api/nodejs-api), [Kotlin](https://kcl-lang.github.io/docs/reference/xlang-api/kotlin-api), [Swift](https://kcl-lang.github.io/docs/reference/xlang-api/swift-api), [C](https://kcl-lang.github.io/docs/reference/xlang-api/c-api), [C++](https://kcl-lang.github.io/docs/reference/xlang-api/cpp-api), [WASM](https://www.kcl-lang.io/docs/reference/xlang-api/wasm-api) 和 [REST API](https://kcl-lang.io/docs/reference/xlang-api/rest-api) 满足不同场景和应用使用需求 +- **生态集成**:通过 [Kustomize KCL 插件](https://github.com/kcl-lang/kustomize-kcl), [Helm KCL 插件](https://github.com/kcl-lang/helm-kcl), [KPT KCL SDK](https://github.com/kcl-lang/kpt-kcl-sdk), [Kubectl KCL 插件](https://github.com/kcl-lang/kubectl-kcl) 或者 [Crossplane KCL 函数](https://github.com/kcl-lang/crossplane-kcl) 分离数据和逻辑,并直接编辑或校验资源 +- **生产可用**:广泛应用在蚂蚁集团平台工程及自动化的生产环境实践中 + +虽然 KCL 不是通用语言,但它有相应的应用场景。开发人员可以通过 KCL 编写**config**、**schema**、**function**和**rule**,其中 config 用于定义数据,schema 用于描述数据的模型定义,rule 用于验证数据,schema 和 rule 还可以组合使用模型和约束来充分描述数据。此外,还可以使用 KCL 中的 lambda 纯函数来组织数据代码,封装通用代码,并在需要时直接调用它。 + +KCL 配置通常遵循如下模式: + +$$ +k\ o \ (T) \ v +$$ + +其中,$k$ 是属性名称,$v$ 是属性值,$o$ 是属性运算符,$T$ 是类型注解。由于 KCL 具有类型推导的能力,因此 $T$ 通常可以省略。比如 `deploy = Deployment {}` 就是一个符合该模式的简单示例。 + +下面是一个用 KCL 生成 Kubernetes 资源的例子 + +```python +apiVersion = "apps/v1" +kind = "Deployment" +metadata = { + name = "nginx" + labels.app = name +} +spec = { + replicas = 3 + selector.matchLabels = metadata.labels + template.metadata.labels = metadata.labels + template.spec.containers = [ + { + name = metadata.name + image = "${metadata.name}:1.14.2" + ports = [{ containerPort = 80 }] + } + ] +} +``` + +我们可以使用上述 KCL 代码生成一个 Kubernetes YAML 配置 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +## 如何选择 + +目前社区已经进行了大量的尝试来改进其配置技术,主要可分为三类: + +- 用于模板、修补和验证的基于低级数据格式的工具,使用外部工具来增强重用和验证。 +- 领域特定语言(DSL)和配置语言(CL),以增强语言能力。 +- 基于通用语言(GPL)的解决方案,使用 GPL 的云开发工具包(CDK)或框架来定义配置。 + +简单的选择答案: + +- 如果您需要编写结构化的静态的 K-V,或使用 Kubernetes 原生的技术工具,建议选择 YAML。 +- 如果您希望引入编程语言便利性以消除文本(如 YAML、JSON) 模板,有良好的可读性,或者你已是 Terraform 的用户,建议选择 HCL。 +- 如果您希望引入类型功能提升稳定性,维护可扩展的配置文件,建议选择 CUE。 +- 如果您希望以现代语言方式编写复杂类型和建模,维护可扩展的配置文件,原生的纯函数和策略,和生产级的性能和自动化,建议直接选择 KCL 或将 KCL 用于对已有配置手段或工具进行增强。 + +### vs. YAML/JSON + +YAML/JSON 适用于小型配置场景。对于需要频繁修改的大型云原生配置场景,它们更适合 KCL。所涉及的主要区别是配置数据抽象和部署之间的区别: + +使用 KCL 进行配置的优点是:对于静态数据,抽象一层的优点意味着整个系统具有部署灵活性。不同的配置环境、租户和运行时可能对静态数据有不同的要求,甚至不同的组织可能有不同的规范和产品要求。KCL 可用于公开最需要的和经常修改的配置。 + +### vs. Jsonnet/GCL + +GCL 是一种用 Python 实现的声明式配置语言,它提供了支持模板抽象的必要语言功能。然而 GCL 编译器本身是用Python编写的,且语言本身是解释执行的。对于大型模板实例(如 kubernetes 模型),性能较差。 + +Jsonnet 是一种用 C++ 实现的数据模板语言,适用于应用程序和工具开发人员,可以生成配置数据并通过代码组织、简化和管理大型配置,而不会产生副作用。 + +Jsonnet 和 GCL 非常擅长减少样板。它们都可以使用代码生成配置,就像工程师只需要编写高级 GPL 代码,而不是手动编写容易出错且难以理解的服务器二进制代码一样。Jsonnet 减少了 GCL 的一些复杂性,但在很大程度上属于同一类别。两者都有许多运行时错误,类型检查和约束能力不足。 + +### vs. HCL + +HCL 是一种 Go 实现的结构化配置语言。HCL 的原生语法受到 libucl 和 nginx 配置的启发。它用于创建一种对人类和机器友好的结构化配置语言,作为 [Terraform 语言](https://www.terraform.io/language)主要用于 DevOps工具、服务器配置和资源配置等。 + +HCL 的用户界面不能通过 Terraform Provider Schema 定义直接感知。此外,在编写复杂对象和必需/可选字段定义时,用户界面很麻烦。动态参数受变量的条件字段约束。资源本身的约束需要由提供程序模式定义,或者与 Sentinel/Rego 和其他策略语言相结合。语言本身的完整性不能自我封闭,其实现方法也不统一。 + +### vs. CUE + +CUE 可以通过结构、无继承和其他特性用作建模,当模型定义之间没有冲突时可以实现高度抽象。因为 CUE 在运行时执行所有约束检查,所以它在大规模配置建模场景中可能存在性能瓶颈。CUE 将类型和值组合为一个概念,并通过各种语法简化了约束的编写。例如,不需要泛型类型和枚举,求和类型和空值合并是一回事。CUE 支持配置合并,但它是完全幂等的。它可能无法满足复杂的多租户和多环境配置场景的要求。对于复杂的循环和约束场景,编写起来很复杂,编写需要精确配置修改或者 Patch 的场景也很麻烦。 + +对于 KCL,建模是通过 KCL Schema 进行的,通过语言级工程和一些面向对象的特性(如单一继承、Mixin 复用)可以实现高模型抽象。KCL 是一种静态编译语言,用于大规模建模场景是运行时开销较低 (性能更高,更低的内存消耗)。KCL 提供了更丰富的检查声明性约束语法,这使得配置和策略编写更加容易。对于一些配置字段组合约束,它更容易编写(与 CUE 相比,KCL 提供了更多的 if-guard 组合约束、all/any/map/filter 表达式和其他集合约束编写方法,这使得编写更容易)。 + +### vs. Dhall + +Dhall 是一种可编程配置语言,它组合了 JSON、函数、类型和 imports 导入等功能, 本身风格偏向函数式,如果您学过 Haskell 等函数式风格语言,可能会对它感到熟悉的。相比于 Dhall, KCL 也提供了类似功能的组合,提供给用户配置可编程和抽象的能力,不过 KCL 在建模、约束检查、自动化等方面做了更多的改进,同时能够通过包管理手段进行模型共享。此外,KCL 的语法语义更贴近于面向对象语言,在一定程度上会比纯函数式风格接受程度更高。 + +### vs. Nickel + +Nickel 是一种简单的配置语言。它的目的是自动生成静态配置文件,本质上是带有函数和类型的 JSON。 + +KCL 和 Nickel 都有类似的渐进式类型系统(静态+动态)、合并策略、函数和约束定义。不同之处在于 KCL 是一种类似 Python 的语言,而 Nickel 是一种类似 JSON 的函数式语言。此外,KCL 提供了 schema 关键字来区分配置定义和配置数据,以避免混合使用。 + +### vs. Starlark + +Starlark 主要用作 Bazel 的配置语言并且是 Python 的一种方言。它没有类型,并且禁止递归。 + +KCL 一定程度上也可以看作 Python 的变种,但是它极大地增强了静态类型和配置扩展性相关的设计,并且是一个编译型语言,这与 Starlark 有着本质的不同。 + +### vs. Pkl + +Pkl 是一门配置即代码语言,它具有可编程、可扩展和安全的特性。 + +KCL 和 Pkl 之间有一些相似之处: + +- 语言特征:Schema 定义、验证、不变性等。 +- 多语言绑定,KCL 为 Python、Go 和 Java 语言等提供了绑定,Pkl 也提供了诸如 Java, Swift 和 Kotlin 等语言绑定。 +- 支持多种 IDE 插件:NeoVim、VS Code等。 + +不同的是,KCL 提供了更多与云原生工具和模型代码库更多的集成。 + +### vs. Kustomize + +Kustomize 的核心功能是其文件级覆盖功能。但是它存在多个覆盖链的问题,因为找到特定属性值的语句不能保证它是最终值,因为其他地方出现的另一个特定值可以覆盖它。对于复杂的场景,Kustomize 文件的继承链的检索通常不如 KCL 代码的继承链检索方便,需要仔细考虑指定的配置文件覆盖顺序。此外,Kustomize 无法解决 YAML 配置编写、约束验证、模型抽象和开发等问题,更适合于简单的配置场景。 + +在 KCL 中,配置合并操作可以对代码中的每个配置属性进行细粒度处理,合并策略可以灵活设置,而不限于整体资源,配置之间的依赖关系可以通过KCL的import语句进行静态分析。 + +### vs. Helm + +Helm 的概念源于操作系统的包管理机制。它是一个基于模板化 YAML 文件的包管理工具,支持包中资源的执行和管理。 + +KCL 自然提供了 Helm 功能的超集以及 Helm KCL 插件,因此您可以直接使用 KCL 作为替代。对于采用 Helm 的用户,KCL 中的堆栈编译结果可以打包并以 Helm 格式使用,通过 kpm 包管理工具进行分发复用。此外,我们还可以直接使用 Helm-KCL 插件直接对已有的 Helm Charts 进行无侵入的可编程扩展。 + +### vs. CDK + +用 CDK 的高级语言编写可以很好地集成到应用程序项目中,这实际上是客户端运行时的一部分。对于 KCL,由 KCL 编写的外部配置和策略与客户端运行时分离。 + +通用语言通常远远超出了需要解决的问题,例如安全问腿、能力边界问题(启动本地线程、访问 IO、网络、代码无限循环和其他安全风险)。例如,在音乐领域,有专门的音符来表达音乐,这便于学习和交流,它不能用一般语言表达清楚。 + +此外,由于通用语言风格多样,需要统一维护、管理和自动化。通用语言通常用于编写客户端运行时,它是服务器运行时的延续,不适合编写独立于运行时的配置,被编译成二进制文件,并最终从进程开始运行。此外,GPL 稳定性和可扩展性不易控制。然而,KCL 配置语言通常用于编写数据,将数据与简单逻辑相结合,它描述了预期的最终结果,然后由编译器或引擎使用,既具备丰富的编程抽象能力,又具备方便的数据处理方式。此外,KCL 是声明式且结构化的,我们可以使用 KCL 的自动化 API 来对 KCL 代码本身进行修改和查询。 + +### vs. OPA/Rego + +Rego 起源于逻辑编程,它基于 Datalog,是一种受限制的 Prolog 形式,而 KCL 基于静态类型结构,具备部分 OOP 特性。Rego 是一种优秀的查询语言。但对于约束强制执行,它有点麻烦,因为实际上首先需要查询要应用约束的值才能进行校验。此外,Rego 本身不具备定义 Schema 的能力,您可以在需要时在 Rego 的注释中引入 JsonSchema 定义。 + +此外,KCL 的方法更易于找到规范化、简化、面向人类易读,面向运行时性能优良的约束和校验表示,具备静态类型,并且它更适合于从 OpenAPI 生成或者创建 OpenAPI。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/kcl-quick-start.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/kcl-quick-start.md new file mode 100644 index 000000000..d3422cbc5 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/getting-started/kcl-quick-start.md @@ -0,0 +1,169 @@ +--- +sidebar_position: 3 +--- + +# KCL 语言速览 + +KCL 是一个面向云原生配置策略领域的编程语言。KCL 设计之初受 Python3 启发,同时吸收了声明式、OOP 编程范式的设计理念,是一种专用于配置策略定义、校验的静态强类型的面向配置和策略场景的语言。本节我们将快速展示 KCL 语言的基本特性。 + +## 1. Hello KCL + +学习新语言的最佳途径是自己亲手写几个小程序,配置语言也是如此。KCL 作为一种配置策略语言,我们可以像写配置一样写 KCL 程序。 + +下面是一个简单的 `hello.k` 程序: + +```python +hello = "KCL" +``` + +将 `hello` 属性设置为 `"KCL"` 字符串。然后将代码保存到 `hello.k` 文件中。 + +如何执行这个程序取决于具体的开发环境,我们先假设本地的 macOS 或者是 Linux 系统已经安装了 `kcl` 命令(或者通过 `docker run --rm -it kcllang/kcl` 进入 Docker 环境测试)。然后在文件所在的目录命令行输入以下命令执行: + +```shell +kcl hello.k +``` + +输出为 + +```yaml +hello: KCL +``` + +命令行执行的效果如图所示: + +![](/img/docs/user_docs/getting-started/hello.gif) + +输出的是 YAML 格式的配置数据。这个程序虽然简单,但是我们可以通过执行 KCL 配置程序到输出结果验证了开发环境和 `kcl` 命令行的基本用法。 + +## 2. 再复杂一点的配置 + +常见的配置数据除了的普通的 key-value 对,还有嵌套的字典和列表类型,同时 value 基础类型除了字符串还有布尔和数值等类型。下面是更为复杂一点的 `server.k` 配置: + +```python +# This is a KCL document + +title = "KCL Example" + +owner = { + name = "The KCL Authors" + data = "2020-01-02T03:04:05" +} + +database = { + enabled = True + ports = [8000, 8001, 8002] + data = [["delta", "phi"], [3.14]] + temp_targets = {cpu = 79.5, case = 72.0} +} + +servers = [ + {ip = "10.0.0.1", role = "frontend"} + {ip = "10.0.0.2", role = "backend"} +] +``` + +其中 `#` 开头的表示行注释。`owner` 的 value 是一个字典,字典的面值通过 `{}` 方式包含的内容,字典内部的 key-value 和 `hello = "KCL"` 例子的写法类似。`database` 则是另一个字典,其中字典属性的 value 出现了布尔 `True`、列表 `[]` 和 `{}` 字典,其中列表和字典中还出现了数值类型的 value。 最后一个 `servers` 属性则是一个列表,列表内部嵌套着字典(字典和列表以及后续将要讲到的 `schema` 都可以相互嵌套)。 + +运行命令和配置输出的 YAML 结果如下: + +```shell +kcl server.k +``` + +```yaml +title: KCL Example +owner: + name: The KCL Authors + data: "2020-01-02T03:04:05" +database: + enabled: true + ports: + - 8000 + - 8001 + - 8002 + data: + - - delta + - phi + - - 3.14 + temp_targets: + cpu: 79.5 + case: 72.0 +servers: + - ip: 10.0.0.1 + role: frontend + - ip: 10.0.0.2 + role: backend +``` + +## 3. schema 定义配置的结构 + +KCL 通过 `schema` 语法结构为有着固定属性结构和默认值行为的属性提供抽象支持。 + +比如上面例子的中 `database` 的配置一般是用默认值即可。这样我们可以通过为数据库的默认配置定义一个结构: + +```python +schema DatabaseConfig: + enabled: bool = True + ports: [int] = [8000, 8001, 8002] + data: [[str|float]] = [["delta", "phi"], [3.14]] + temp_targets: {str: float} = {cpu = 79.5, case = 72.0} +``` + +`enabled` 是布尔类型;`ports` 为整数列表类型;`data` 为列表的列表,内层的列表元素是字符串或者浮点数类型;`temp_targets` 则是一个字典类型,字典的属性值是浮点数类型。并且 `DatabaseConfig` 的每个属性都定义了默认值。 + +然后通过 `database = DatabaseConfig {}` 就可以产生和默认值相同属性的结构。用户也可以修改默认值: + +```python +database = DatabaseConfig { + ports = [2020, 2021] +} +``` + +`schema DatabaseConfig` 不仅仅为属性提供了默认值,还为属性添加了类型信息。因此,如果用户不小心写错属性值类型的话,KCL 将会给出友好的错误提示,比如下面的例子将 `ports` 错误地写成了浮点数类型: + +```python +database = DatabaseConfig { + ports = [1.2, 1.3] +} +``` + +执行时将产生类似以下的错误(显示的文件路径和本地环境有关): + +```shell +kcl server.k +``` + +输出为 + +```shell +error[E2G22]: TypeError + --> /path/to/server.k:8:5 + | +8 | ports = [1.2, 1.3] + | ^ expected [int], got [float(1.2)|float(1.3)] + | + + --> /path/to/server.k:3:5 + | +3 | ports: [int] = [8000, 8001, 8002] + | ^ variable is defined here, its type is [int], but got [float(1.2)|float(1.3)] + | +``` + +类似地我们可以用以下的代码封装 `servers` 部分的属性: + +```python +schema ServerConfig: + ip: str + role: "frontend" | "backend" + +servers = [ + ServerConfig {ip = "10.0.0.1", role = "frontend"} + ServerConfig {ip = "10.0.0.2", role = "backend"} +] +``` + +其中 `ServerConfig` 的 `ip` 是字符串类型,并没有给出默认值。用户在生成 `ServerConfig` 类型的属性时必须手工添加 `ip` 属性的值,否则 KCL 将会报出缺少必填属性的错误。`role` 属性是 `"frontend" | "backend"` 枚举字符串类型。 + +此外,`schema` 还可以结合 `check`、`mixin`、可选属性、继承和扩展模块实现更为复杂的配置和策略数据的抽象,细节可以参考手册部分的文档。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/_category_.json new file mode 100644 index 000000000..1fdf894e2 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "用户手册", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/abstraction.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/abstraction.md new file mode 100644 index 000000000..05b46dc46 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/abstraction.md @@ -0,0 +1,151 @@ +--- +title: "抽象" +sidebar_position: 3 +--- + +## 什么是抽象 + +抽象是指一个实体的简化表示,它允许隐藏特定的具体细节,同时向程序员提供最相关的信息。每一个抽象都是为满足特定需求而定制的,并且可以极大地提高给定实体的可用性。在 KCL 的上下文中,抽象可以使代码更容易理解和维护,同时也可以简化用户界面。 + +需要注意的是,代码抽象并不是为了减少代码大小,而是为了提高代码的可维护性和可扩展性。在抽象代码的过程中,应考虑可重用性、可读性和可扩展性等因素,并根据需要对代码进行不断优化。 + +良好的抽象可以提供如下价值 + +1. 提供不同的焦点,不同角色和场景关注点分离。 +2. 屏蔽较低级别的细节,避免潜在的错误。 +3. 提升用户界面和自动化友好性。 + +KCL 自身可能不会评估用户定义模型抽象的合理性,但它提供了技术解决方案来帮助用户构建抽象。 + +## 使用 KCL 进行抽象 + +现在,让我们将 Docker Compose 和 Kubernetes 资源抽象为应用程序配置 + +`Docker Compose` 是一个用于定义和运行多容器 Docker 应用程序的工具。使用 Docker Compose,您可以在一个文件中定义应用程序的服务、网络和卷,然后使用它作为一个单元启动和停止应用程序。Docker Compose 通过处理网络、存储和其他基础设施问题的细节,简化了运行复杂的多容器应用程序的过程。 + +Kubernetes 清单是定义 Kubernete 对象(如 Pods、Deployments 和 Services)的 YAML 文件。清单提供了一种声明性的方法来定义应用程序的所需状态,包括副本数量、要使用的镜像和网络配置。Kubernetes 使用清单来创建和管理部署和运行应用程序所需的资源。 + +以下是一些参考资料,可以帮助了解更多关于 Docker Compose 和 Kubernetes 相关的信息: + +- [Docker Compose 文档](https://docs.docker.com/compose/) +- [Kubernetes 对象文档](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/) + +以应用程序为中心的开发使开发人员能够专注于其工作负载的体系结构,而不是目标环境、基础设施或平台中的技术栈。我们用 `App` 结构定义了应用程序模型,然后使用 KCL CLI 将其翻译到多个平台,例如不同版本的 `Docker Compose` 或 `Kubernetes`。该应用程序模型旨在通过只需定义一个跨多个平台工作的 KCL 文件来减少开发人员的工作量和认知负荷。现在,让我们学习如何做到这一点。 + +### 0. 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +### 1. 获取示例 + +首先,我们执行 git 命令获得用例 + +```bash +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/abstraction +``` + +我们可以运行以下命令来显示配置。 + +```bash +cat main.k +``` + +输出为 + +```python +import .app + +app.App { + name = "app" + containers.nginx = { + image = "nginx" + ports = [{containerPort = 80}] + } + service.ports = [{ port = 80 }] +} +``` + +在上面的代码中,我们使用 `App` schema 定义了一个配置,其中我们配置了一个 `nginx` 容器,并开启 `80` 端口配置。 + +此外,KCL 允许开发人员以声明式的方式定义应用程序所需的资源,并允许生成特定于平台的配置文件,如 `docker_compose.yaml` 或 Kubernetes `manifests.yaml` 文件。接下来,让我们生成相应的配置。 + +### 2. 将应用配置转换为 Docker Compose 配置 + +如果我们想将应用程序配置转换为 Docker Compose 配置,我们可以简单地运行如下命令: + +```shell +kcl main.k docker_compose_render.k +``` + +输出为 + +```yaml +services: + app: + image: nginx + ports: + - published: 80 + target: 80 + protocol: TCP +``` + +### 3. 将应用配置转换为 Kubernetes Deployment and Service 资源清单 + +如果我们想将应用程序配置转换为 Kubernetes 清单,我们可以简单地运行如下命令: + +```shell +kcl main.k kubernetes_render.k +``` + +输出为 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: app + labels: + app: app +spec: + replicas: 1 + selector: + matchLabels: + app: app + template: + metadata: + labels: + app: app + spec: + containers: + - name: nginx + image: nginx + ports: + - protocol: TCP + containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: app + labels: + app: app +spec: + selector: + app: app + ports: + - port: 80 + protocol: TCP +``` + +如果您想了解有关应用程序模型的更多信息,可以参考[此处](https://github.com/kcl-lang/kcl-lang.io/tree/main/examples/abstraction). + +## 小结 + +通过使用 KCL,我们能够分离模型的抽象和实现细节,允许将抽象模型映射到各种基础设施或平台。这是通过不同实现之间的灵活切换和 KCL 组合编译来实现的,以屏蔽配置差异,减轻认知负担。 + +## 更多信息 + +想了解 KCL 是如何实现抽象的能力的?可以参阅[KCL 教程](/docs/reference/lang/tour)学习更多 KCL 语言功能。 + +除了手动维护配置外,我们还可以使用 KCL API 将**自动配置更改能力**集成到我们的应用程序中。有关 KCL 自动化能力的相关说明,请参阅[此处](/docs/user_docs/guides/automation)。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/automation.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/automation.md new file mode 100644 index 000000000..19c2b05bf --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/automation.md @@ -0,0 +1,195 @@ +--- +title: "自动化" +sidebar_position: 6 +--- + +## 简介 + +在 KCL 中提供了很多自动化相关的能力,主要包括工具和多语言 API。 通过 `package_identifier : key_identifier`的模式支持对任意配置键值的索引,从而完成对任意键值的增删改查。比如下图所示修改某个应用配置的镜像内容,可以直接执行如下指令修改镜像,修改前后的 diff 如下图所示。 + +![](/img/blog/2022-09-15-declarative-config-overview/14-kcl-image-update.png) + +此外,KCL 的自动化能力也可以被集成到 CI/CD 中。 + +![](/img/blog/2022-09-15-declarative-config-overview/15-kcl-automation.png) + +## 使用 KCL 进行自动化 + +### 0. 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +### 1. 获得示例 + +```bash +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/automation +``` + +我们可以执行如下命令显示配置 + +```bash +cat main.k +``` + +输出为 + +```python +schema App: + """The application model.""" + name: str + replicas: int + labels?: {str:str} = {app = name} + +app: App { + name = "app" + replicas = 1 + labels.key = "value" +} +``` + +我们可以执行如下命令输出配置 + +```bash +kcl main.k +``` + +输出为 + +```yaml +app: + name: app + replicas: 1 + labels: + app: app + key: value +``` + +### 2. 使用 KCL CLI 进行自动化 + +KCL 允许使用通过 CLI `-O|--overrides` 参数修改配置模型中的值,这个参数通常由三个部分组成: 包名 `pkg`, 配置标识符 `identifier`, 配置属性 `attribute` 和覆盖值 `override_value` + +```bash +kcl main.k -O override_spec +``` + +- `override_spec`: 表示需要修改的配置模型字段和值的统一表示 + +```bash +override_spec: identifier (("=" | ":" | "+=") value | "-") +``` + +- `identifier`: 表示需要修改配置的标识符,通常为 `a.b.c` 或者 `a["dot.key"].c` 的形式 +- `value`: 表示需要修改配置的值,可以是任意合法的 KCL 表达式,比如数字/字符串字面值,list/dict/schema 表达式等 +- `=`, `-` 和 `+=`: 表示用对应的属性运算符修改 identifier 的值 + - 当 identifier 存在时,修改已有 identifier的值为 value + - 当 identifier 不存在时,添加 identifier属性,并将其值设置为 value +- `-`: 表示删除 identifier属性 + - 当 identifier 存在时,直接进行删除 + - 当 identifier 不存在时,对配置不作任何修改 + +请注意,当 `identifier` 出现多次时,修改/删除全部 `identifier` 的值 + +#### 修改配置 + +执行如下命令可以更新应用名称: + +```bash +kcl main.k -O app.name=\'new_app\' +``` + +输出为 + +```yaml +app: + name: new_app + replicas: 1 + labels: + app: new_app + key: value +``` + +可以看出 `app` 的 `name` 属性的值被修改为了 `new_app` + +此外,当我们使用 KCL CLI `-d` 参数时,KCL 文件将同时修改为以下内容 + +```bash +kcl main.k -O app.name=\'new_app\' -d +``` + +```python +schema App: + """The application model.""" + name: str + replicas: int + labels?: {str:str} = {app = name} + +app: App { + name = "new_app" + replicas = 1 + labels: {key = "value"} +} +``` + +注意当配置块中 `app` 的 `name` 属性不存在时, 它会被新增到配置块中。 + +#### 删除配置 + +执行如下命令可以删除 `labels` 中的 `key` 字段 + +```bash +kcl main.k -O app.labels.key- +``` + +输出为: + +```yaml +app: + name: app + replicas: 1 + labels: + app: app +``` + +### 3. 使用 KCL API 进行自动化 + +此外,我们还可以通过[多语言 API](/docs/reference/xlang-api/overview) 自动修改配置属性 + +以 RestAPI 为例 + +执行如下命令启动 RestAPI 服务端 + +```bash +kcl server +``` + +通过如下命令 POST 命令请求配置修改服务 + +```bash +curl -X POST http://127.0.0.1:2021/api:protorpc/KclvmService.OverrideFile -H 'content-type: accept/json' -d '{ + "file": "main.k", + "specs": ["app.name=\"nginx\""] +}' +``` + +服务调用完成后,`main.k` 会被修改为如下形式: + +```python +schema App: + """The application model.""" + name: str + replicas: int + labels?: {str:str} = {app = name} + +app: App { + name = "nginx" + replicas = 1 + labels: { + "key" = "value" + } +} +``` + +## 小结 + +该文档介绍了KCL的自动化功能,包括工具和多语言 API。它支持对任何配置的键值进行索引,允许添加、删除、修改和查询任何键值。它也可以集成到 CI/CD 中。本文档提供了一个使用 KCL 自动化配置管理的示例,包括使用 KCL CLI/API 覆盖和删除配置。更多信息请参阅[此处](/docs/reference/lang/tour#KCL-cli-variable-Override)。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/1-github-actions.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/1-github-actions.md new file mode 100644 index 000000000..b93fdec92 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/1-github-actions.md @@ -0,0 +1,166 @@ +--- +id: github-actions +sidebar_label: Github Actions +--- + +# Github Actions 集成 + +## 简介 + +在 GitOps 章节,我们介绍了如何将 KCL 与 GitOps 进行集成。在本文中,我们将继续提供 KCL 和 CI 集成的示例方案,希望通过使用容器、用于生成的持续集成 (CI) 和用于持续部署 (CD) 的 GitOps 来实现端到端应用程序开发流程。在此方案中,我们使用一个 Flask 应用和 Github Actions 将用作示例。 + +> 注意:你可以在此方案中使用任何容器化应用以及不同的 CI 系统如 Gitlab CI,Jenkins CI 等。 + +整体工作流程如下: + +- 应用代码开发并提交到提交到 GitHub 存储库 +- GitHub Actions 从应用代码生成容器镜像,并将容器镜像推送到 docker.io 容器注册表 +- GitHub Actions 根据 docker.io 容器注册表中容器镜像的版本号并同步更新 KCL 清单部署文件 + +## 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +## 具体步骤 + +### 1. 获得示例 + +我们将业务源码和部署清单放在不同仓库,可以分不同角色进行分别维护,实现关注点分离。 + +- 获得业务源码 + +```shell +git clone https://github.com/kcl-lang/flask-demo.git/ +cd flask-demo +``` + +这是一个使用 Python 编写的 Web 应用,我们可以使用应用目录的 `Dockerfile` 来生成这个应用的容器镜像,同时可以通过 Github CI 自动构建 `flask_demo` 镜像,CI 配置如下 + +```yaml +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [main] + pull_request: + branches: [main] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Docker Login + uses: docker/login-action@v1.10.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + logout: true + + # Runs a set of commands using the runners shell + - name: build image + run: | + make image + docker tag flask_demo:latest ${{ secrets.DOCKER_USERNAME }}/flask_demo:${{ github.sha }} + docker push ${{ secrets.DOCKER_USERNAME }}/flask_demo:${{ github.sha }} + + # Trigger KCL manifest + - name: Trigger CI + uses: InformaticsMatters/trigger-ci-action@1.0.1 + with: + ci-owner: kcl-lang + ci-repository: flask-demo-kcl-manifests + ci-ref: refs/heads/main + ci-user: kcl-bot + ci-user-token: ${{ secrets.DEPLOY_ACCESS_TOKEN }} + ci-name: CI + ci-inputs: >- + image=${{ secrets.DOCKER_USERNAME }}/flask_demo + sha-tag=${{ github.sha }} +``` + +我们需要源码仓库的工作流自动触发部署清单仓库中的工作流,此时需要创建具有 Github CI 操作权限的 `secrets.DEPLOY_ACCESS_TOKEN` 以及 Docker Hub 镜像推送的账号信息 `secrets.DOCKER_USERNAME` 和 `secrets.DOCKER_PASSWORD`, 这些可以在 Github 仓库的 `Secrets and variables` 设置中进行配置,如下图所示 + +![](/img/docs/user_docs/guides/ci-integration/github-secrets.png) + +### 2. 提交应用代码 + +flask-demo 仓库提交代码后,Github 会自动构建容器镜像,并将制品推送到 Docker hub 中,会再触发 flask-demo-kcl-manifests 仓库的 Action,[通过 KCL 自动化 API](/docs/user_docs/guides/automation) 修改部署清单仓库中的镜像地址。现在让我们为 flask-demo 仓库创建一个提交,我们可以看到代码提交后触发业务仓库 Github CI 流程 + +![](/img/docs/user_docs/guides/ci-integration/app-ci.png) + +### 3. 配置自动更新 + +当业务仓库 Github CI 流程执行完成后,会自动在存放 KCL 资源配置的仓库触发一个 CI 自动更新配置并提交到 flask-demo-kcl-manifests main 分支,commit 信息如下 + +![](/img/docs/user_docs/guides/ci-integration/image-auto-update.png) + +- 我们可以获得部署清单源码进行编译验证 + +```shell +git clone https://github.com/kcl-lang/flask-demo-kcl-manifests.git/ +cd flask-demo-kcl-manifests +git checkout main && git pull && kcl +``` + +输出 YAML 为 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flask_demo + labels: + app: flask_demo +spec: + replicas: 1 + selector: + matchLabels: + app: flask_demo + template: + metadata: + labels: + app: flask_demo + spec: + containers: + - name: flask_demo + image: "kcllang/flask_demo:6428cff4309afc8c1c40ad180bb9cfd82546be3e" + ports: + - protocol: TCP + containerPort: 5000 +--- +apiVersion: v1 +kind: Service +metadata: + name: flask_demo + labels: + app: flask_demo +spec: + type: NodePort + selector: + app: flask_demo + ports: + - port: 5000 + protocol: TCP + targetPort: 5000 +``` + +从上述配置可以看出资源的镜像确实自动更新为了新构建的镜像内容。此外,我们还可以使用 Argo CD KCL 插件 自动从 Git 存储库同步或从中拉取数据并将应用部署到 Kubernetes 集群。 + +## 小结 + +通过将 KCL 和 Github CI 集成,我们能够将任意的业务代码的产出容器化镜像进行自动化修改并部署配置,以实现端到端应用程序开发流程并提升研发部署效率。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_2-gitlab-ci.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_2-gitlab-ci.md new file mode 100644 index 000000000..5ec96ce99 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_2-gitlab-ci.md @@ -0,0 +1,12 @@ +--- +id: gitlab-ci +sidebar_label: Gitlab CI +--- + +Coming Soon + +## Introduction + +## How to + +## Summary diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_3-jenkins-ci.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_3-jenkins-ci.md new file mode 100644 index 000000000..f85d231f4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_3-jenkins-ci.md @@ -0,0 +1,12 @@ +--- +id: github-ci +sidebar_label: Github CI +--- + +Coming Soon + +## Introduction + +## How to + +## Summary diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_category_.json new file mode 100644 index 000000000..3145ed7f0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/ci-integration/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "CI Integration", + "position": 12 +} \ No newline at end of file diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/configuration.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/configuration.md new file mode 100644 index 000000000..0327747fd --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/configuration.md @@ -0,0 +1,129 @@ +--- +title: "配置" +sidebar_position: 1 +--- + +## 简介 + +配置是软件系统的一个重要方面,由于不断发展的业务需求、基础设施需求和其他因素,这些系统会不断发生变化。通常,快速改变这些系统的行为可能具有挑战性,尤其是当这样做需要昂贵且耗时的重建和重新部署过程时。在这种情况下,仅仅对业务代码进行更改可能是不够的。幸运的是,配置提供了一种低开销的方式来修改系统功能。 + +我们可以根据需要将静态配置存储在 JSON 或 YAML 等文件中。此外,配置也可以存储在高级语言中,从而实现更灵活的配置。这种语言可以进行编码、呈现和静态配置。KCL 是一种提供此类功能的配置语言。开发人员可以编写 KCL 代码来生成 JSON/YAML 和其他配置。 + +## 使用 KCL 编写配置代码 + +KCL 的核心特性是其**建模**和**约束**能力,KCL 核心功能基本围绕 KCL 这个两个核心特性展开,对于代码而言(包括配置代码)都存在对配置数据约束的需求,比如类型约束、配置字段必选/可选约束、范围约束、不可变性约束等,这也是 KCL 致力于解决的核心问题之一。 + +现在我们已经了解了 KCL 的基本功能,让我们探索如何使用它来生成配置。 + +### 0. 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +### 1. 获取示例 + +首先,执行如下命令获取示例 + +```shell +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/configuration +``` + +我们可以执行如下命令显示配置代码 + +```shell +cat nginx.k +``` + +输出为: + +```python +schema Nginx: + """Schema for Nginx configuration files""" + http: Http + +schema Http: + server: Server + +schema Server: + listen: int | str # The attribute `listen` can be int type or a string type. + location?: Location # Optional, but must be non-empty when specified + +schema Location: + root: str + index: str + +nginx = Nginx { + http.server = { + listen = 80 + location = { + root = "/var/www/html" + index = "index.html" + } + } +} +``` + +### 2. 使用 KCL 生成 YAML + +执行如下命令: + +```bash +kcl nginx.k +``` + +我们可以获得如下 YAML 输出 + +```yaml +nginx: + http: + server: + listen: 80 + location: + root: /var/www/html + index: index.html +``` + +### 3. 为配置添加动态参数 + +此外,我们可以通过 KCL 内置函数 `option` 动态接收外部参数。例如,对于下面的 KCL 文件(db.k),我们可以使用命令行 `-D` 标志来接收外部动态参数。 + +```python +env: str = option("env") or "dev" # The attribute `env` has a default value "den" +database: str = option("database") +hosts = { + dev = "postgres.dev" + stage = "postgres.stage" + prod = "postgres.prod" +} +dbConfig = { + host = hosts[env] + database = database + port = "2023" + conn = "postgres://${host}:${port}/${database}" +} +``` + +```bash +# Use the `-D` flag to input external parameters. +kcl db.k -D database="foo" +``` + +输出为 + +```yaml +env: dev +database: foo +hosts: + dev: postgres.dev + stage: postgres.stage + prod: postgres.prod +dbConfig: + host: postgres.dev + database: foo + port: "2023" + conn: "postgres://postgres.dev:2023/foo" +``` + +## 小结 + +通过使用 KCL,我们可以生成更低低级别的数据配置。此外,我们通过 `-D` 标志设置动态参数以满足不同的场景需求。有关更多 KCL 的功能和教程,请参阅[此处](/docs/reference/lang/tour)。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/data-integration.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/data-integration.md new file mode 100644 index 000000000..e42c910b8 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/data-integration.md @@ -0,0 +1,117 @@ +--- +title: "数据集成" +sidebar_position: 4 +--- + +## 简介 + +在 KCL 中,不仅可以将 KCL 编写的配置代码编译输出为 YAML 格式的数据,还可以将 JSON/YAML 等数据直接嵌入到 KCL 语言当中。 + +## 使用 KCL 进行数据集成 + +### 0. 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +### 1. 获得示例 + +```bash +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/data-integration +``` + +### 2. YAML 集成 + +我们可以运行以下命令来显示 KCL YAML 集成配置。 + +```bash +cat yaml.k +``` + +```python +import yaml + +schema Server: + ports: [int] + +server: Server = yaml.decode("""\ +ports: +- 80 +- 8080 +""") +server_yaml = yaml.encode({ + ports = [80, 8080] +}) +``` + +在上述代码中,我们通过 KCL 内置的 `yaml` 模块以及其中的 `yaml.decode` 直接完成 YAML 数据的集成,并且使用 `Server` schema 对集成的 YAML 数据直接进行校验。此外,我们可以使用 `yaml.encode` 完成 YAML 数据的序列化。 + +我们通过如下命令可以获得配置输出: + +```shell +kcl yaml.k +``` + +输出为 + +```yaml +server: + ports: + - 80 + - 8080 +server_yaml: | + ports: + - 80 + - 8080 +``` + +此外,KCL 支持使用 `file` 模块从文件中读取数据,您可以从文件中读取 YAML 数据并进行进一步的操作与修改。 + +```python +import file +import yaml + +deployment = yaml.decode(file.read("deployment.yaml")) | { + metadata.name = "override_name" +} +``` + +### 3. JSON 集成 + +同样的,对于 JSON 数据,我们可以使用 `json.encode` 和 `json.decode` 函数以同样的方式进行数据集成。 + +我们可以运行以下命令来显示 KCL JSON 集成配置。 + +```bash +cat json.k +``` + +```python +import json + +schema Server: + ports: [int] + +server: Server = json.decode('{"ports": [80, 8080]}') +server_json = json.encode({ + ports = [80, 8080] +}) +``` + +执行命令输出为: + +```shell +kcl json.k +``` + +```yaml +server: + ports: + - 80 + - 8080 +server_json: '{"ports": [80, 8080]}' +``` + +## 小结 + +本文介绍了如何在 KCL 中进行数据集成,使用 KCL 内置的 yaml 和 json 包将 YAML 和 JSON 数据直接集成到 KCL 语言中,并使用相应的解码和编码功能对其进行验证和序列化。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/1-argocd.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/1-argocd.md new file mode 100644 index 000000000..d552119b4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/1-argocd.md @@ -0,0 +1,145 @@ +--- +id: gitops-quick-start +sidebar_label: 使用 ArgoCD 支持 KCL 实现 GitOps +--- + +# 快速开始 + +## 简介 + +### 什么是 GitOps + +GitOps 是一种实现持续交付的现代方式。它的核心思想是拥有一个包含环境和应用程序配置的 Git 存储库。通过更改应用存储库中的文件,可以自动部署应用程序。应用 GitOps 的好处包括: + +- 提高生产力,持续交付可以加快部署时间。 +- 降低开发人员部署的障碍。通过推送代码而不是容器配置,开发人员可以在不知道其内部实现的情况下轻松部署 Kubernetes 集群和应用。 +- 追踪变更记录。使用 Git 管理配置使每一项更改都具有可跟踪性,从而增强审计跟踪。 + +### 将 KCL 与 ArgoCD 一起使用 + +将 [KCL](https://github.com/kcl-lang/kcl) 与 [ArgoCD](https://github.com/argoproj/argo-cd) 等 GitOps 工具一起使用具有如下好处: + +- 通过 KCL 语言的[抽象能力](/docs/user_docs/guides/abstraction)和可编程能力可以帮助我们**简化复杂的 Kubernetes 部署配置文件**,降低手动编写 YAML 文件的错误率,消除多余的配置模版,提升多环境多租户的配置扩展能力,同时提高配置的可读性和可维护性。 +- KCL 允许开发人员以声明式的方式定义应用程序所需的资源,通过将 KCL 和 ArgoCD 相结合可以帮助我们更好地实现**基础设施即代码(IaC)**,提高部署效率,简化应用程序的配置管理。 +- ArgoCD 可以**自动化**地实现应用程序的连续部署,并提供友好的可视化界面。 + +使用 GitOps,开发人员和运维团队可以通过分别修改应用和配置代码来管理应用程序的部署,GitOps 工具链将自动同步对配置的更改,从而实现持续部署并确保一致性。如果出现问题,可以使用 GitOps 工具链快速回滚。 + +## 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +## 快速开始 + +### 1. 获取示例 + +首先,我们执行 git 命令获得用例 + +```bash +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/gitops +``` + +我们可以运行以下命令来显示配置 + +```bash +cat config/main.k +``` + +The output is + +```python +import .app + +config = app.App { + name = "kcl-guestbook-ui" + containers.guestbook = { + image = "gcr.io/heptio-images/ks-guestbook-demo:0.2" + ports = [{containerPort = 80}] + } + service.ports = [{ port = 80 }] + service.type = "LoadBalancer" +} +``` + +在上述代码中,我们定义使用 `App` schema 定义了应用的配置,其中我们配置了一个镜像为 `gcr.io/heptio-images/ks-guestbook-demo:0.2` 容器,并启用了 `80` 端口。 + +### 2. 安装 Kubernetes 和 GitOps 工具 + +#### 配置 Kubernetes 集群和 ArgoCD 控制器 + +- 安装 [K3d](https://github.com/k3d-io/k3d) 并创建一个集群 + +```bash +k3d cluster create mycluster +``` + +> 注意:你可以在此方案中使用其他方式创建您自己的 Kubernetes 集群,如 kind, minikube 等。 + +- 安装 [ArgoCD](https://github.com/argoproj/argo-cd/releases/). + +```bash +kubectl create namespace argocd +kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml +``` + +- 安装 ArgoCD KCL 插件 + +```bash +kubectl apply -f ./install/kcl-cmp.yaml && kubectl -n argocd patch deploy/argocd-repo-server -p "$(cat ./install/patch-argocd-repo-server.yaml)" +``` + +- 通过 `kubectl get` 命令查看 argocd 控制器容器是否初始化完成进入运行(Running)状态。 + +```bash +kubectl get pod -n argocd -l app.kubernetes.io/name=argocd-repo-server +``` + +- 通过如下命令打开 ArgoCD UI + +```bash +kubectl port-forward svc/argocd-server -n argocd 8080:443 +``` + +- 打开浏览器 `https://localhost:8080` 输入用户名 "admin" 和密码登陆 ArgoCD UI,密码可以通过如下命令得到: + +```bash +kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d +``` + +#### 安装 ArgoCD 客户端工具 + +- 安装 [ArgoCD 客户端工具](https://github.com/argoproj/argo-cd/releases) + +- 使用用户名 "admin" 和刚才得到的密码登陆 + +```bash +argocd login localhost:8080 +``` + +通过如下命令创建一个 ArgoCD KCL 应用 + +```bash +argocd app create guestbook \ +--repo https://github.com/kcl-lang/kcl-lang.io \ +--path examples/gitops/config \ +--dest-namespace default \ +--dest-server https://kubernetes.default.svc \ +--config-management-plugin kcl-v1.0 +``` + +如果创建成功,您可以看到如下输出: + +```bash +application 'guestbook' created +``` + +> 如果您使用的是私有存储库,则在执行 create 命令之前,需要使用私钥凭据配置专用私有存储库访问权限。请参阅[这里](https://argo-cd.readthedocs.io/en/stable/user-guide/private-repositories/)以获取更多详细信息。 + +通过 ArgoCD UI,您可以看到创建的应用程序尚未同步,您可以手动进行配置同步或设置为自动同步。 + +![](/img/docs/user_docs/guides/gitops/argocd-kcl-app.jpg) + +有关同步策略的更多信息,可以请参阅[这里](https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/) + +![](/img/docs/user_docs/guides/gitops/argocd-kcl-app-dashboard.jpg) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/2-fluxcd.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/2-fluxcd.md new file mode 100644 index 000000000..fcc98cb2b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/2-fluxcd.md @@ -0,0 +1,112 @@ +--- +id: gitops-with-fluxcd +sidebar_label: 使用 flux-kcl-controller 支持 KCL 与 FluxCD 实现 GitOps +--- + +# 快速开始 + +## 简介 + +### 什么是 GitOps + +GitOps 是一种实现持续交付的现代方式。它的核心思想是拥有一个包含环境和应用程序配置的 Git 存储库。通过更改应用存储库中的文件,可以自动部署应用程序。应用 GitOps 的好处包括: + +- 提高生产力,持续交付可以加快部署时间。 +- 降低开发人员部署的障碍。通过推送代码而不是容器配置,开发人员可以在不知道其内部实现的情况下轻松部署 Kubernetes 集群和应用。 +- 追踪变更记录。使用 Git 管理配置使每一项更改都具有可跟踪性,从而增强审计跟踪。 + +### 将 KCL 与 FluxCD 一起使用 + +将 [KCL](https://github.com/kcl-lang/kcl) 与 [FluxCD](https://github.com/fluxcd/flux2) 等 GitOps 工具一起使用具有如下好处: + +- 通过 KCL 语言的[抽象能力](/docs/user_docs/guides/abstraction)和可编程能力可以帮助我们**简化复杂的 Kubernetes 部署配置文件**,降低手动编写 YAML 文件的错误率,消除多余的配置模版,提升多环境多租户的配置扩展能力,同时提高配置的可读性和可维护性。 +- KCL 允许开发人员以声明式的方式定义应用程序所需的资源,通过将 KCL 和 FluxCD 相结合可以帮助我们更好地实现**基础设施即代码(IaC)**,提高部署效率,简化应用程序的配置管理。 +- FluxCD 可以**自动化**地实现应用程序的连续部署,并提供友好的可视化界面。 + +使用 GitOps,开发人员和运维团队可以通过分别修改应用和配置代码来管理应用程序的部署,GitOps 工具链将自动同步对配置的更改,从而实现持续部署并确保一致性。如果出现问题,可以使用 GitOps 工具链快速回滚。 + +### Flux-KCL-Controller + +kcl-controller 是一个组件,用于集成 [KCL](https://github.com/kcl-lang/kcl) 和 [Flux](https://github.com/fluxcd/flux2), 主要用来根据存储在 git/oci 仓库中的 KCL 程序定义的基础设施和工作负载,通过 [source-controller](https://github.com/fluxcd/source-controller) 获取 KCL 程序,实现基础设施和工作负载的持续交付。 + +![](/img/docs/user_docs/guides/cd-integration/kcl-flux.png) + +## 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +## 快速开始 + +### 1. 安装 Kubernetes 和 GitOps 工具 + +#### 配置 Kubernetes 集群和 FluxCD 控制器 + +- 安装 [K3d](https://github.com/k3d-io/k3d) 并创建一个集群 + +```bash +k3d cluster create mycluster +``` + +> 注意:你可以在此方案中使用其他方式创建您自己的 Kubernetes 集群,如 kind, minikube 等。 + +- 安装 Flux KCL Controller + +```bash +git clone https://github.com/kcl-lang/flux-kcl-controller.git && cd flux-kcl-controller && make deploy +``` + +- 通过 `kubectl get` 命令查看 fluxcd 控制器容器是否初始化完成进入运行(Running)状态。 + +```bash +kubectl get pod -n source-system -l app=kcl-controller +``` + +### 2. 编写 Flux-KCL-Controller 配置文件 + +以[《使用 Github、Argo CD 和 KCL 实现 GitOps 以简化 DevOps》](https://kcl-lang.io/zh-CN/blog/2023-07-31-kcl-github-argocd-gitops/) 中的 flask demo 为例,我们在 `flux-kcl-controller` 仓库中创建一个 `GitRepository` 对象,用于监控存储在 git 仓库中的 KCL 程序。将一下内容保存在文件 `gitrepo.yaml` 中。 + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: kcl-deployment + namespace: default +spec: + interval: 10s # 每隔 10 秒检查 + url: https://github.com/kcl-lang/flask-demo-kcl-manifests.git + ref: + branch: main # 监控 main 分支 +--- +apiVersion: krm.kcl.dev.fluxcd/v1alpha1 +kind: KCLRun +metadata: + name: kcl-git-controller + namespace: default +spec: + sourceRef: + kind: GitRepository + name: kcl-deployment +``` + +通过命令 `kubectl apply -f gitrepo.yaml` 部署对象到集群。 + +### 3. 查看部署结果 + +通过 `kubectl get deployments` 命令查看 python flask demo 部署结果。 + +``` +kubectl get deployments +``` + +可以看到结果,部署成功 + +``` +NAME READY UP-TO-DATE AVAILABLE AGE +flask-demo 1/1 1 1 17d +``` + +### 4. 更多内容 + +- [FluxCD 官方文档](https://toolkit.fluxcd.io/) +- [Flux Source Controller 官方文档](https://fluxcd.io/flux/components/source/) +- [GitRepositrory](https://fluxcd.io/flux/components/source/gitrepositories/) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/_category_.json new file mode 100644 index 000000000..29a73c67a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/gitops/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "GitOps", + "position": 11 +} \ No newline at end of file diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/index.md new file mode 100644 index 000000000..722a488a8 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/index.md @@ -0,0 +1,7 @@ +# 用户手册 + +用户指南包括常见场景和使用 KCL 的快速入门示例。你可以点击下面的列表进行练习。如果你想学习 KCL 语言的所有语法,可以参考[这里](/docs/reference/lang/tour) + +import DocCardList from '@theme/DocCardList'; + + diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/3-quick-start.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/3-quick-start.md new file mode 100644 index 000000000..d3008c1e4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/3-quick-start.md @@ -0,0 +1,106 @@ +# 快速开始 + +## 0. 前置条件 + +- 安装 [kcl](https://kcl-lang.io/docs/user_docs/getting-started/install/) + +## 1. 初始化一个空的 KCL 包 + +使用 `kcl mod init` 命令创建一个名为 `my_package` 的 kcl 程序包, 并且在我们创建完成一个名为 `my_package` 的包后,我们需要通过命令 `cd my_package` 进入这个包来进行后续的操作。 + +```shell +kcl mod init my_package && cd my_package +``` + +`kcl` 将会在执行`kcl mod init my_package`命令的目录下创建两个默认的配置文件 `kcl.mod` 和 `kcl.mod.lock`。 + +```shell +- my_package + |- kcl.mod + |- kcl.mod.lock + |- # 你可以直接在这个目录下写你的kcl程序。 +``` + +`kcl.mod.lock` 是 `kcl` 用来固定依赖版本的文件,是自动生成的,请不要人工修改这个文件。 + +`kcl` 将会为这个新包创建一个默认的 `kcl.mod`。如下所示: + +```shell +[package] +name = "my_package" +edition = "0.0.1" +version = "0.0.1" +``` + +## 2. 为 KCL 包添加依赖 + +然后,您可以通过 `kcl mod add` 命令来为您当前的库添加一个外部依赖。 + +如下面的命令所示,为当前包添加一个版本号为 `1.28` 并且名为 `k8s` 的依赖包。 + +```shell +kcl mod add k8s:1.28.1 +``` + +`kcl` 会为您将依赖添加到 kcl.mod 文件中. + +```shell +[package] +name = "my_package" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +k8s = "1.28.1" # The dependency 'k8s' with version '1.28.1' +``` + +## 编写一个程序使用包 `konfig` 中的内容 + +在当前包中创建 `main.k`。 + +```shell +- my_package + |- kcl.mod + |- kcl.mod.lock + |- main.k # Your KCL program. +``` + +并且将下面的内容写入 `main.k` 文件中。 + +```kcl +# 导入并使用外部依赖 `k8s` 包中的内容。 +import k8s.api.core.v1 as k8core + +k8core.Pod { + metadata.name = "web-app" + spec.containers = [{ + name = "main-container" + image = "nginx" + ports = [{containerPort = 80}] + }] +} + +``` + +## 3. 运行 KCL 代码 + +你可以使用 kcl 编译刚才编写的 `main.k` 文件, 得到编译后的结果。 + +```shell +kcl run +``` + +输出为 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: web-app +spec: + containers: + - image: nginx + name: main-container + ports: + - containerPort: 80 +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/10-kpm_git.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/10-kpm_git.md new file mode 100644 index 000000000..a246a1729 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/10-kpm_git.md @@ -0,0 +1,33 @@ +# 使用 Git 仓库 + +KCL 包管理工具支持通过 OCI registry 和 Git 仓库保存和分享 KCL 包。本文将介绍如何使用 KCL 包管理工具与私有 OCI registry 和 Git 仓库集成。由于 Git 命令行工具提供了登录/push/pull等功能,因此,KCL 包管理工具将不再提供同样的功能,KCL 包管理工具仅支持通过 `kcl mod add` 命令将 git 仓库添加为当前 KCL 包的三方库。 + +## 私有 Git 仓库 + +KCL 包管理工具依赖本地环境中的 Git 工具完成与 Git 仓库的交互。因此,在使用 KCL 包管理工具之前,确保本地环境中完成了 Git 工具的安装,并且在环境变量 $PATH 中能够找到 Git 命令。 + +更多信息 - [如何安装 Git 工具](https://git-scm.com/downloads) + +KCL 包管理工具与本地环境中的 Git 工具公用一份登录凭证,当您使用 KCL 包管理工具与私有 Git 仓库交互时,您需要先检查 Git 工具能否正常与私有 Git 仓库交互。如果您使用 `git clone` 命令能够成功下载私有 Git 仓库,您可以直接使用 KCL 包管理工具而不需要进行任何登录操作。 + +更多信息 - [使用 Git 下载私有仓库](https://docs.github.com/zh/repositories/creating-and-managing-repositories/cloning-a-repository) + +## 添加 Git 仓库作为一个三方库依赖 + +你可以使用 `kcl mod add` 命令将 Git 仓库添加为当前 KCL 包的三方库依赖。 + +以 `https://github.com/kcl-lang/konfig` 为例,命令如下: + +```shell +kcl mod add git://github.com/kcl-lang/konfig --tag v0.4.0 # 添加一个带有 tag 的 Git 仓库 +kcl mod add git://github.com/kcl-lang/konfig --commit 78ba6e9 # 添加一个带有 commit 的 Git 仓库 +kcl mod add git://github.com/kcl-lang/konfig --branch main # 添加一个带有 branch 的 Git 仓库 +``` + +如上所示的方式是使用 Https 协议将 Git 仓库添加为一个依赖。你也可以使用 `ssh` 协议或其他协议将 Git 仓库添加为一个依赖,如下所示: + +```shell +kcl mod add --git https://github.com/kcl-lang/konfig --tag v0.4.0 # 添加一个带有 tag 的 Git 仓库和 Https 协议 +kcl mod add --git https://github.com/kcl-lang/konfig --branch main # 添加一个带有 branch 的 Git 仓库和 Https 协议 +kcl mod add --git ssh://github.com/kcl-lang/konfig --commit 78ba6e9 # 添加一个带有 commit 的 Git 仓库和 ssh 协议 +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/4-share_your_pkg.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/4-share_your_pkg.md new file mode 100644 index 000000000..d3d435aae --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/4-share_your_pkg.md @@ -0,0 +1,73 @@ +# 发布 KCL 包到 ghcr.io + +本文将指导您如何使用 kcl 包管理将您的 kcl 包推送到发布到 OCI Registry 中。kcl 包管理默认使用 [ghcr.io](https://ghcr.io) 作为 OCI Registry, 您可以通过修改 kcl 包管理配置文件来更改默认的 OCI Registry。关于如何修改 kcl 包管理配置文件的信息,请参阅 [kcl oci registry](https://github.com/kcl-lang/kpm/blob/main/docs/kpm_oci-zh.md#kpm-registry) + +下面是一个简单的步骤,指导您如何使用 kcl 包管理将您的 kcl 包推送到 ghcr.io。 + +## 步骤 1:安装 KCL CLI + +首先,您需要在您的计算机上安装 KCL CLI。您可以按照 [KCL CLI 安装文档](https://kcl-lang.io/zh-CN/docs/user_docs/getting-started/install)中的说明进行操作。 + +## 步骤 2:创建一个 ghcr.io 令牌 + +如果您使用默认的 OCI Registry, 要将 kcl 包推送到 ghcr.io,您需要创建一个用于身份验证的令牌。您可以参考以下文档。 + +- [创建 ghcr.io token](https://docs.github.com/zh/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) + +## 步骤 3:登录 ghcr.io + +在安装了 kcl 包管理并创建了 ghcr.io 令牌后,您需要使用 kcl 包管理登录 ghcr.io。您可以使用以下命令进行操作: + +```shell +kcl registry login -u -p ghcr.io +``` + +其中 `` 是您的 GitHub 用户名,`` 是您在步骤 2 中创建的令牌。 + +关于如何使用 kcl 包管理登录 ghcr.io 的更多信息,请参阅 [kcl registry login](https://www.kcl-lang.io/zh-CN/docs/tools/cli/package-management/command-reference/login)。 + +## 步骤 4:推送您的 kcl 包 + +现在,您可以使用 kcl 包管理将您的 kcl 包推送到 ghcr.io。 + +### 1. 一个合法的 kcl 包 + +首先,您需要确保您推送的内容是符合一个 kcl 包的规范,即必须包含合法的 kcl.mod 和 kcl.mod.lock 文件。 + +如果您不知道如何得到一个合法的 `kcl.mod` 和 `kcl.mod.lock`。您可以使用 `kcl mod init` 命令。 + +```shell +# 创建一个名为 my_package 的 kcl 包 +kcl mod init my_package +``` + +`kcl mod init my_package` 命令将会为您创建一个新的 kcl 包 `my_package`, 并为这个包创建 `kcl.mod` 和 `kcl.mod.lock` 文件。 + +如果您已经有了一个包含 kcl 文件的目录 `exist_kcl_package`,您可以使用以下命令将其转换为一个 kcl 包,并为其创建合法的 `kcl.mod` 和 `kcl.mod.lock`。 + +```shell +# 在 exist_kcl_package 目录下 +pwd +/home/user/exist_kcl_package + +# 执行 kcl 包管理init 命令来创建 kcl.mod 和 kcl.mod.lock +kcl mod init +``` + +关于如何使用 kcl 包管理init 的更多信息,请参阅 [kcl mod init](https://kcl-lang.io/zh-CN/docs/tools/cli/package-management/command-reference/init)。 + +### 2. 推送 kcl 包 + +您可以在 `kcl` 包的根目录下使用以下命令进行操作: + +```shell +# 在 exist_kcl_package 包的根目录下 +pwd +/home/user/exist_kcl_package + +# 推送 kcl 包到默认的 OCI Registry +kcl mod push +``` + +完成上述步骤后,您就成功地将您的 kcl 包推送到了默认的 OCI Registry 中。 +关于如何使用 kcl mod push 的更多信息,请参阅 [kcl mod push](https://kcl-lang.io/zh-CN/docs/tools/cli/package-management/command-reference/push)。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/5-share_your_pkg_docker.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/5-share_your_pkg_docker.md new file mode 100644 index 000000000..83d2e1f3d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/5-share_your_pkg_docker.md @@ -0,0 +1,65 @@ +# 发布 KCL 包到 docker.io + +本文将指导您如何使用 kcl 包管理将您的 kcl 包推送到发布到 docker.io 中。 + +## 步骤 1:安装 KCL CLI + +首先,您需要在您的计算机上安装 KCL CLI。您可以按照 [KCL CLI 安装文档](https://kcl-lang.io/zh-CN/docs/user_docs/getting-started/install)中的说明进行操作。 + +## 步骤 2:创建一个 docker.io 账户 + +您需要创建一个 docker.io 账户以支持您的 kcl 包的推送。 + +## 步骤 3:登录 docker.io + +您可以直接使用 docker.io 的账户名和密码登录。 + +```shell +kcl registry login -u -p docker.io +``` + +其中 `` 是您的 docker.io 用户名,`` 是您 docker.io 账户的密码。 + +关于如何使用 KCL CLI 登录 docker.io 的更多信息,请参阅 [kcl registry login](https://www.kcl-lang.io/zh-CN/docs/tools/cli/package-management/command-reference/login)。 + +## 步骤 4:推送您的 kcl 包 + +现在,您可以使用 KCL CLI 将您的 kcl 包推送到 docker.io。 + +### 1. 一个合法的 kcl 包 + +首先,您需要确保您推送的内容是符合一个 kcl 包的规范,即必须包含合法的 kcl.mod 和 kcl.mod.lock 文件。 + +如果您不知道如何得到一个合法的 `kcl.mod` 和 `kcl.mod.lock`。您可以使用 `kcl mod init` 命令。 + +例如:创建一个名为 my_package 的 kcl 包 + +```shell +# 创建一个名为 my_package 的 kcl 包 +kcl mod init my_package +``` + +`kcl mod init my_package` 命令将会为您创建一个新的 kcl 包 `my_package`, 并为这个包创建 `kcl.mod` 和 `kcl.mod.lock` 文件。 + +如果您已经有了一个包含 kcl 文件的目录 `exist_kcl_package`,您可以使用以下命令将其转换为一个 kcl 包,并为其创建合法的 `kcl.mod` 和 `kcl.mod.lock`。 + +在 `exist_kcl_package` 目录下执行: + +```shell +kcl mod init +``` + +关于如何使用 kcl mod init 的更多信息,请参阅 [kcl mod init](https://kcl-lang.io/zh-CN/docs/tools/cli/package-management/command-reference/init)。 + +### 2. 推送 kcl 包 + +您可以在 `kcl` 包的根目录下使用以下命令进行操作: + +在 `exist_kcl_package` 包的根目录下, 执行 + +```shell +kcl mod push oci://docker.io//exist_kcl_package +``` + +完成上述步骤后,您就成功地将您的 kcl 包 `exist_kcl_package` 推送到了 docker.io 中。 +关于如何使用 kcl mod push 的更多信息,请参阅 [kcl mod push](https://kcl-lang.io/zh-CN/docs/tools/cli/package-management/command-reference/push)。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/6-push_github_action.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/6-push_github_action.md new file mode 100644 index 000000000..2f18b66f2 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/6-push_github_action.md @@ -0,0 +1,83 @@ +# 如何在 github action 中使用 kcl 包管理发布您的 KCL 包 + +本文将指导您如何在 GitHub Action 中使用 kcl 包管理将您的 kcl 包推送到发布到 ghcr.io 中。 + +## 步骤 1:安装 KCL CLI + +首先,您需要在您的计算机上安装 KCL CLI。您可以按照 [KCL CLI 安装文档](https://kcl-lang.io/zh-CN/docs/user_docs/getting-started/install)中的说明进行操作。 + +## 步骤 2:创建一个 GitHub 账号 + +如果您已经有 GitHub 帐号了,您可以选择跳过这一步 + +[注册新的一个 GitHub 账号](https://docs.github.com/zh/get-started/signing-up-for-github/signing-up-for-a-new-github-account) + +## 步骤 3: 为您的 KCL 包创建一个 GitHub 仓库并进行相关配置 + +### 1. 为您的 KCL 程序包准备仓库 + +您需要为您的 KCL 程序包准备一个 GitHub 仓库。 + +[创建一个 GitHub 仓库](https://docs.github.com/zh/get-started/quickstart/create-a-repo) + +在这个仓库中添加您的 KCL 程序,以仓库 https://github.com/awesome-kusion/catalog.git 为例, + +```bash +├── .github +│ └── workflows +│ └── push.yaml # github action 文件 +├── LICENSE +├── README.md +├── kcl.mod # kcl.mod 将当前仓库内容定义为一个 kcl 包 +├── kcl.mod.lock # kcl.mod.lock 是 kcl 包管理工具自动生成的文件 +└── main.k # 您的 KCL 程序 +``` + +### 2. 为您的仓库设置 OCI Registry,账户和密码 + +以 docker.io 为例,您可以为您的仓库设置 secrets `REG`, `REG_ACCOUNT` 和 `REG_TOKEN`。`REG` 的值为 `docker.io`,`REG_ACCOUNT` 的值为您的 docker.io 账户, `REG_TOKEN` 为您的 `docker.io` 登录密码。 + +[为仓库添加 secrets](https://docs.github.com/zh/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) + +如果您使用 `ghcr.io` 作为 `Registry`, 您需要使用 GitHub token 作为 secrets。 + +[创建一个 GitHub Token](https://docs.github.com/zh/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-tokens-classic) + +## 步骤 4: 将您的 KCL 包添加到仓库中并编写 github action workflow + +为这个仓库添加 github action 文件 `.github/workflows/push.yml`,内容如下: + +```yaml +name: KPM Push Workflow + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Go 1.21 + uses: actions/setup-go@v2 + with: + go-version: 1.21 + + - name: Install KCL CLI + run: go install kcl-lang.io/cli/cmd/kcl@latest + + - name: Login and Push + env: + # 通过环境变量指定 OCI Registry 和账户 + KPM_REG: ${{ secrets.REG }} + KPM_REPO: ${{ secrets.REG_ACCOUNT }} + # kcl registry login 时使用 secrets.REG_TOKEN + run: kcl registry login -u ${{ secrets.REG_ACCOUNT }} -p ${{ secrets.REG_TOKEN }} ${{ secrets.REG }} && kcl mod push + + - name: Run KCL project from oci registry + run: kcl run oci://${{ secrets.REG }}/${{ secrets.REG_ACCOUNT }}/catalog --tag 0.0.1 +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/7-publish_pkg_to_ah.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/7-publish_pkg_to_ah.md new file mode 100644 index 000000000..4f6ae139c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/7-publish_pkg_to_ah.md @@ -0,0 +1,142 @@ +# 将您的 KCL 包发布到 ArtifactHub + +我们已经将 [(ArtifactHub, AH)](https://artifacthub.io/) 集成为 KCL 模块的市场,并且我们维护一个 github 仓库 [`modules`](https://github.com/kcl-lang/modules) 用来保存发布到 AH 的 KCL 模块。如果您希望将您的 KCL 模块发布到我们的市场,您可以通过提交 PR 的方式将您的 KCL 模块提交到这个仓库中。 + +## 注意事项 + +在您提交 PR 之前,有一些事情您需要仔细考虑: + +- `modules` 仓库中的所有 KCL 模块的源代码都是**公开的**,如果您希望您的 KCL 模块是私有的,抱歉我们目前不支持,您可以尝试通过构建您自己的仓库来解决这个问题。 + +- 如果您希望将您的 KCL 模块发布到 `modules` 中并且能够在 AH 上被找到,**您的 KCL 模块必须带有一个版本号,并且版本号必须符合 [语义化版本](https://semver.org/) 的定义**,即 kcl.mod 中的 `version` 字段是非空的,并且符合语义化版本的定义。 + +``` +[package] +name = "mynginx" +edition = "*" +version = "0.0.1" # 这个字段不可以为空,并且必须符合语义化版本的定义。 +``` + +- **一旦一个 KCL 模块的某个版本被发布,其内容就不能被改变。我们不允许 KCL 模块的内容在不改变模块版本的情况下被改变**。也就是说,如果您提交了一个 PR,改变了 KCL 模块的内容,并且您希望所有人都能够使用您所做的改变,那么您必须升级您的 KCL 模块的版本,即改变 kcl.mod 中的 `version` 字段。如果您遇到了某些特殊情况必须要改变某个版本的 KCL 模块内容,请在仓库中提出 issue 并且联系我们。 + +## 快速开始 + +在下一节中,我们通过 `helloworld` 示例向您展示如何发布您的 KCL 包并且在 AH 上找到他们。 + +### 准备工作 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) +- 安装 [git](https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git) +- [注册一个 Github 账户(可选)](https://docs.github.com/zh/get-started/signing-up-for-github/signing-up-for-a-new-github-account) + +### 代码仓库 + +注意:如果您希望将您的 KCL 包发布到 `kcl-lang` 官方的 Registry 中,那么您的 KCL 包的源代码将以开源的形式保存在当前仓库中,您需要将您的包的源代码通过 PR 提交到这个仓库中。 + +### 准备您的 KCL 包 + +通过 `kcl mod init ` 命令, 您可以创建一个合法的 KCL 程序模块。 + +目前,仓库能够识别的合法的程序的目录结构如下: + +``` + + |- kcl.mod (必选的) + |- kcl.mod.lock (可选的) + |- artifacthub-pkg.yaml (可选的) + |- README.md (可选的) + |- (*.k) kcl program files +``` + +- kcl.mod : 作为 KCL 程序包的标识文件,这个文件**必选的**,包含 kcl.mod 文件的目录会被标识为文件的根目录。 +- kcl.mod.lock : 自动生成的用来固定依赖版本的文件,这个文件**可选的**,不需要手动改动。 +- artifacthub-pkg.yaml : 这个文件是**可选的**,因为我们的仓库目前通过 artifacthub 展示所有的包,通过 artifacthub-pkg.yaml 来配置您想要包的信息,这里我们采取的策略是**如果在您的包的 kcl.mod 文件所在目录中有一个名为 artifacthub-pkg.yaml 的配置文件,那么,我们将使用您提供 artifacthub-pkg.yaml 来展示您的包的信息,否则,我们将会使用一些默认的信息生成对应的 artifacthub-pkg.yaml 文件。** +- README.md : 一个 markdown 文件作为您的包的文档,这个文件是**可选的**,**如果您不提供这个文件,artifacthub 上将不会展示您的包的文档。** +- (\*.k) kcl program files: 您的 KCL 程序的源代码。 + +### 通过 PR 发布您的包 + +#### 1. 下载代码仓库 + +首先,您需要使用 git 将仓库 https://github.com/kcl-lang/modules 下载到您的本地 + +```shell +git clone https://github.com/kcl-lang/modules --depth=1 +``` + +#### 2. 为您的包创建一个分支 + +我们推荐您的分支名为:publish-pkg-, 为您包的名称。 + +以包 helloworld 为例 + +进入您下载的 modules 目录中 + +```shell +cd modules +``` + +为包 helloworld 创建一个分支 `publish-pkg-helloworld` + +```shell +git checkout -b publish-pkg-helloworld +``` + +#### 3. 添加您的包 + +您需要将您的包移动到当前目录下,在我们的例子中,我们使用 `kcl mod init` 命令创建包 helloworld + +```shell +kcl mod init helloworld +``` + +您可以为 helloworld 包增加一个 README.md 文件保存在包的根目录下,用来展示在 AH 的首页中。 + +```shell +echo "## Introduction" >> helloworld/README.md +echo "This is a kcl module named helloworld." >> helloworld/README.md +``` + +#### 4. 提交您的包 + +您可以使用如下命令提交您的包 + +使用 `git add .` 命令将您的包添加到 git 的暂存区中 + +```shell +git add . +``` + +使用 `git commit -s` 命令提交您的包, 我们推荐您的 commit message 遵循 “publish module ” 的格式。 + +```shell +git commit -m "publish module helloworld" -s +``` + +使用 `git push` 命令将您的包提交到您的分支 publish-pkg- 中 + +```shell +git push +``` + +#### 5. 提交 PR + +将您的分支 publish-pkg- 向仓库的 main 分支提交 PR。 + +- [如何创建 PR](https://docs.github.com/zh/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) + +### 通过 PR 升级您的包 + +完成包的内容上传后,您可以通过 PR 升级您的包。 + +注意:**我们没有提供任何改变包的内容但是不改变版本号的升级策略。** 如果您想要升级您的包,并希望您升级后的包被展示在 AH 上,您需要修改您的包的版本号。即在 kcl.mod 文件的 module 章节中的 version 字段。 + +```toml +[package] +name = "my_module" +edition = "*" +version = "0.1.0" # 改变这个字段来升级您的包 +description = "This is my module." +``` + +同样,**您无法多次上传同一个版本号的 KCL 包**,一旦您的包的版本号已经被使用,您将无法再次使用这个版本号,再次上传这个包的方式就只有升级版本号。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/8-kcl_mod.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/8-kcl_mod.md new file mode 100644 index 000000000..a24d2b27a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/8-kcl_mod.md @@ -0,0 +1,243 @@ +# kcl.mod: KCL 包清单文件 + +## 1. KCL 包清单 + +每个模块的 `kcl.mod` 文件都被称为其清单。它采用 TOML 格式编写,包含编译模块所需的元数据。 + +目前 `kcl.mod` 中支持如下内容: + +- 包元数据: + - [package](#package) - 定义一个包。 + - [name](#package) — 包的名称。 + - [version](#package) — 包的版本。 + - [edition](#package) — KCL 编译器版本。 + - [description](#package) — 包的描述。 + - [include](#include) - 在打包和发布时包含的文件。 + - [exclude](#exclude) - 在打包和发布时排除的文件。 +- 依赖表: + - [dependencies](#dependencies) - 包库依赖项。 +- 编译器设置: + - [profile](#entries) - 编译器设置。 + - [entries](#entries) - 编译包的入口点。 + +## 2. package + +`kcl.mod` 中的第一个部分是 `[package]`。主要包含 `name`, `version`, `edition` 和 `description` 字段。 + +### 2.1. name + +`name` 是包的名称,它是一个字符串, 这是一个必要的字段, 注意,包的名称中不可以包含`"."`。 + +例如: 一个包名为 my_pkg 的 kcl 程序包。 + +```toml +[package] +name = "my_pkg" +``` + +### 2.2. version + +`version` 是包的版本,它是一个字符串, 这是一个必要的字段。注意,目前 KCL 程序包的版本号仅支持语义化版本号。 + +例如: `my_pkg` 程序包的版本号为 `0.1.0`。 + +```toml +[package] +name = "my_pkg" +version = "0.1.0" +``` + +### 2.3. edition + +`edition` 是 KCL 编译器版本,它是一个字符串, 这是一个必要的字段。注意,目前 KCL 编译器版本号仅支持语义化版本号。 + +例如: `my_pkg` 程序包的版本号为 `0.1.0`, 并且与 0.5.1 的 KCL 编译器兼容。 + +```toml +[package] +name = "my_pkg" +version = "0.1.0" +edition = "0.5.0" +``` + +### 2.4. description + +`description` 是包的描述,它是一个字符串, 这是一个可选的字段。 + +例如: `my_pkg` 程序包的描述为 `This is my package.`。 + +```toml +[package] +name = "my_pkg" +version = "0.1.0" +edition = "0.5.0" +description = "This is my package." +``` + +### 2.5. include + +你可以使用 `include` 字段指定打包和发布时包含的文件。 + +`include` 是 `package` 部分的字段。 + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "0.5.0" +description = "This is a hello world package." +include = ["src/", "README.md", "LICENSE"] # 打包和发布时包含的文件 +``` + +### 2.6. exclude + +你可以使用 `exclude` 字段指定打包和发布时排除的文件。 + +`exclude` 是 `package` 部分的字段。 + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "0.5.0" +description = "This is a hello world package." +exclude = ["target/", ".git/", "*.log"] # 打包和发布时排除的文件 +``` + +## 3. dependencies + +你的 kcl 包可以依赖于来自 OCI 仓库、Git 存储库或本地文件系统子目录的其他库。 + +### 3.1. oci dependency + +KCL 包管理工具默认将包保存在 oci registry 上,默认使用的 oci registry 是 `ghcr.io/kcl-lang`。 +更多内容关于 oci registry 请参考 [支持 OCI registry](https://kcl-lang.io/docs/user_docs/guides/package-management/how-to/oci_reg_supports)。 + +你可以按照以下方式指定依赖项: + +```toml +[dependencies] + = +``` + +这将会从 oci registry 中拉取名称为 `` 的包,版本为 ``。 + +如果您希望拉取 `k8s` 包的 `1.27` 版本: + +```toml +[dependencies] +k8s = "1.27" +``` + +### 3.2. git dependency + +根据 git 仓库中的 tag 指定对应的依赖。 + +```toml +[dependencies] + = { git = "", tag = "" } +``` + +这将会从 Git 存储库``中拉取名称为 `` 的包,`tag` 为 ``。 + +根据 git 仓库中的 commit id 指定对应的依赖。 + +```toml +[dependencies] + = { git = "", commit = "" } +``` + +这将会从 Git 存储库``中拉取名称为 `` 的包,`commit id` 为 ``。 + +### 3.3 local dependency + +通过 path 指定本地三方库依赖。 + +```toml +[dependencies] + = {path = ""} +``` + +这将会从本地文件路径 `` 中加载名称为 `` 的包。 + +## 4. entries + +你可以在编译时指定包的入口点。 + +`entries` 是 `[profile]` 部分的子部分。entries 是一个字符串数组,包含编译器的入口点。这是一个可选的字段,如果没有指定,则默认为包根目录下的所有 `*.k` 文件。 + +```toml +[profile] +entries = [ + ... +] +``` + +entries 中可以定义绝对路径和相对路径,如果定义的是相对路径,那么就会以当前包的 + +`entries` 是 kcl 包根路径的相对路径,`kcl.mod` 文件路径是包的根路径。支持两种文件路径格式,即 `normal paths` 和 `mod relative paths`。 + +- normal path:相对于当前包的根路径。 +- mod relative path:相对于 kcl.mod 中 [dependencies](#dependencies) 部分中的三方包的根路径。 + +例如: + +1. 如果 `kcl.mod` 位于 `/usr/my_pkg/kcl.mod`,则 `kpm run` 将把 `/usr/my_pkg/entry1.k` 和 `/usr/my_pkg/subdir/entry2.k` 作为 `kcl` 编译器的入口点。 + +``` +entries = [ + "entry1.k", + "subdir/entry2.k", +] +``` + +2. 如果 `kcl.mod` 位于 `/usr/my_pkg/kcl.mod`,并且当前 `kcl` 包依赖于 `kcl` 包 `k8s`。你可以使用 `mod relative paths` 将来自包 `k8s` 中的 `kcl` 文件作为 `kcl` 编译器的入口点。 + +``` +entries = [ + "entry1.k", + "subdir/entry2.k", + "${k8s:KCL_MOD}/core/api/v1/deployment.k" +] +``` + +`mod relative paths` 必须包含前缀 `${k8s:KCL_MOD}`,其中 `k8s` 是包名,`${k8s:KCL_MOD}` 表示包 k8s 的包根路径。因此,如果 `k8s` 的包根路径是 `/.kcl/kpm/k8s`,则上面的 `entries` 将把 `/usr/my_pkg/entry1.k`、`/usr/my_pkg/subdir/entry2.k` 和 `/.kcl/kpm/k8s/core/api/v1/deployment.k` 作为 `kcl` 编译器的入口点。 + +### 注意 + +你可以使用 `normal path` 指定当前包路径中的编译入口点,使用 `mod relative path` 指定三方包中的入口点。 + +因此,使用 `normal path` 制定的文件路径必须来自于同一个包,即从 `normal path` 开始寻找的 `kcl.mod` 路径必须只能找到一个 `kcl.mod` 文件,不然编译器将输出错误。 + +例如: + +在路径 `/usr/kcl1` 下 + +``` +/usr/kcl1 + |--- kcl.mod + |--- entry1.k +``` + +在路径 `/usr/kcl2` 下 + +``` +/usr/kcl2 + |--- kcl.mod + |--- entry2.k +``` + +如果你在路径`/usr/kcl1`下使用这样的 kcl.mod 编译: + +``` +entries = [ + "entry1.k", # 对应的 kcl.mod 文件是 /usr/kcl1/kcl.mod + "/usr/kcl2/entry2.k", # 对应的 kcl.mod 文件是 /usr/kcl2/kcl.mod +] +``` + +将会得到错误: + +``` +error[E3M38]: conflict kcl.mod file paths +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/9-kpm_oci.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/9-kpm_oci.md new file mode 100644 index 000000000..70731630c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/9-kpm_oci.md @@ -0,0 +1,229 @@ +# 使用 OCI Registries + +KCL 包管理工具支持通过 OCI Registries 保存和分享 KCL 包。 + +## 默认 OCI Registry + +KCL 包管理工具默认使用 ghcr.io 保存 KCL 包。 + +默认 registry - [https://github.com/orgs/kcl-lang/packages](https://github.com/orgs/kcl-lang/packages) + +## 自定义 OCI Registry + +有几个支持 OCI 的托管容器 Registry,您可以将其用于存储 KCL 模块。 + +- [Docker Hub](https://docs.docker.com/docker-hub/oci-artifacts/) +- [Harbor](https://goharbor.io/docs/main/administration/user-defined-oci-artifact/) +- [Amazon ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/push-oci-artifact.html) +- [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-oci-artifacts) +- [Google Artifact Registry](https://cloud.google.com/artifact-registry/docs/helm/manage-charts) +- [Alibaba Cloud Container Registry](https://help.aliyun.com/acr/) +- [IBM Cloud Container Registry](https://cloud.ibm.com/docs/Registry) +- [JFrog Artifactory](https://jfrog.com/help/r/jfrog-artifactory-documentation/docker-registry) + +你可以通过以下方法调整 OCI Registry 的地址和仓库名称。 + +### 通过环境变量 + +你可以通过设置三个环境变量 KPM_REG、KPM_REGO 来调整配置。 + +```shell +# 设置默认仓库地址 +export KPM_REG="ghcr.io" +# 设置默认仓库 +export KPM_REPO="kcl-lang" +``` + +### 通过配置文件 + +KCL 包管理工具的配置文件位于 `$KCL_PKG_PATH/.kpm/config/kpm.json`,如果环境变量 `KCL_PKG_PATH` 没有设置,它默认保存在 `$HOME/.kcl/kpm/.kpm/config/kpm.json`。 + +配置文件的默认内容如下: + +```json +{ + "DefaultOciRegistry": "ghcr.io", + "DefaultOciRepo": "kcl-lang" +} +``` + +## 快速开始 + +在接下来的内容中,我们将使用 `localhost:5001` 作为示例 OCI Registry,并且为这个 OCI Registry 添加了一个账户 `test`,密码是 `1234`, 上传一个名称为 `MyPkg` 的 `v0.1.0` 的包。 + +### kcl registry login + +你可以通过以下四种方式使用 `kcl registry login`。 + +#### 1. 使用账户和密码登陆 OCI Registry + +```shell +kcl registry login -u -p +Login succeeded +``` + +对我们的示例来说,命令如下: + +```shell +kcl registry login -u test -p 1234 localhost:5001 +``` + +#### 2. 使用账户登陆 OCI Registry,并且交互式输入密码 + +```shell +kcl registry login -u +Password: +Login succeeded +``` + +对我们的示例来说,命令如下: + +```shell +kcl registry login -u test localhost:5001 +Password: 1234 +Login succeeded +``` + +#### 3. 交互式输入账户和密码登陆 OCI Registry + +```shell +kcl registry login +Username: +Password: +Login succeeded +``` + +对我们的示例来说,命令如下: + +```shell +kcl registry login localhost:5001 +Username: test +Password: 1234 +Login succeeded +``` + +### kcl registry logout + +你可以使用 `kcl registry logout` 退出一个 OCI Registry。 + +```shell +kcl registry logout +``` + +对我们的示例来说,命令如下: + +```shell +kcl registry logout localhost:5001 +``` + +### kcl mod push + +你可以在 kcl 包的根目录下使用 `kcl mod push` 命令将 kcl 包上传到一个 OCI Registry。 + +```shell +# 创建一个新的 kcl 包。 +kcl mod init +# 进入 kcl 包的根目录 +cd +# 将 kcl 包上传到一个 oci registry +kcl mod push +``` + +对于示例来说,命令如下: + +```shell +kcl mod init MyPkg +cd MyPkg +kcl mod push +``` + +你也可以在 `kcl mod push` 命令中指定 OCI registry 的 url。 + +```shell +# 创建一个新的 kcl 包。 +kcl mod init +# 进入 kcl 包的根目录 +cd +# 将 kcl 包上传到一个 oci registry +kcl mod push +``` + +对于示例来说,您可以通过命令来 push kcl 包到 localhost:5001 中 + +```shell +kcl mod init MyPkg +cd MyPkg +kcl mod push oci://localhost:5001/test/MyPkg --tag v0.1.0 +``` + +### kcl mod pull + +你可以使用 `kcl mod pull` 从默认的 OCI registry 中下载一个 kcl 包。kpm 会自动从 `kpm.json` 中的 OCI registry 中寻找 kcl 包。 + +```shell +kcl mod pull : +``` + +对于示例来说,命令如下: + +```shell +kcl mod pull MyPkg:v0.1.0 +``` + +或者,你也可以从指定的 OCI registry url 中下载一个 kcl 包。 + +```shell +kcl mod pull +``` + +对于示例来说,命令如下: + +```shell +kcl mod pull oci://localhost:5001/test/MyPkg --tag v0.1.0 +``` + +### kcl mod add + +你可以使用 `kcl mod add` 从默认的 OCI registry 中添加一个 kcl 包作为当前 kcl 包的三方依赖。kpm 会自动从 `kpm.json` 中的 OCI registry 中寻找 kcl 包。 + +```shell +kcl mod add : +``` + +对于示例来说,命令如下: + +```shell +kcl mod add MyPkg:v0.1.0 +``` + +或者,你也可以从指定的 OCI registry url 中下载一个 kcl 包。 + +```shell +kcl mod add +``` + +对于示例来说,命令如下: + +```shell +kcl mod add oci://localhost:5001/test/MyPkg --tag v0.1.0 +``` + +### kcl run + +KCL 可以直接通过 OCI 的 url 编译 kcl 包。 + +```shell +kcl run +``` + +对于示例来说,命令如下: + +```shell +kcl run oci://localhost:5001/test/MyPkg --tag v0.1.0 +``` + +另外,你也可以通过 OCI 引用来编译 kcl 包。 + +```shell +kcl run : +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/_category_.json new file mode 100644 index 000000000..370cb4e91 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/4-how-to/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "如何使用", + "position": 4 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/_category_.json new file mode 100644 index 000000000..74815a856 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/package-management/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "包管理工具", + "position": 7 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/schema-definition.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/schema-definition.md new file mode 100644 index 000000000..735667b9e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/schema-definition.md @@ -0,0 +1,117 @@ +--- +title: "模型定义" +sidebar_position: 3 +--- + +## 简介 + +KCL 的核心场景是写配置和校验,因此 KCL 被设计之初的一个核心特性就是**建模**,对应到 KCL 的关键字 `schema`,`schema` 可以被用于定义结构和约束,比如字段的类型,默认值,字段的范围和各种其他约束等内容。此外,使用 KCL schema 定义的结构可以反过来用于验证实现、验证输入(JSON、YAML 等结构化数据)或生成代码(生成多语言结构体、OpenAPI 等)。 + +## 使用 KCL 定义结构和约束 + +### 0. 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +### 1. 获得示例 + +```shell +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/definition +``` + +我们可以执行如下命令显示配置 + +```bash +cat main.k +``` + +输出为 + +```python +import .app_module # A relative path import + +app: app_module.App { + domainType = "Standard" + containerPort = 80 + volumes = [ + { + mountPath = "/tmp" + } + ] + services = [ + { + clusterIP = "None" + $type = "ClusterIP" + } + ] +} +``` + +我们将 `App` 模型放入单独的 `app_module.k` 中,在需要时我们可以在 `main.k` 中使用 `import` 关键字进行模块化管理,比如下面的文件结构 + +``` +. +├── app_module.k +└── main.k +``` + +其中 `app_module.k` 的内容为 + +```python +schema App: + domainType: "Standard" | "Customized" | "Global" + containerPort: int + volumes: [Volume] + services: [Service] + + check: + 1 <= containerPort <= 65535 + +schema Service: + clusterIP: str + $type: str + + check: + clusterIP == "None" if $type == "ClusterIP" + +schema Volume: + container: str = "*" # `container` 的默认值为 "*" + mountPath: str + + check: + mountPath not in ["/", "/boot", "/home", "dev", "/etc", "/root"] +``` + +在上面的文件中。在其中,我们使用 `schema` 关键字定义了三个模型 `App`,`Service` 和 `Volume`。并且 `App` 模型具有四个属性 `domainType`, `containerPort`, `volumes` 和 `services`,其中 + +- `domainType` 的类型为字符串字面值联合类型,与“枚举”类似,这表明 `domainType` 的值只能取 `"Standard"`, `"Customized"` 和 `"Global"` 中的一个 +- `containerPort` 的类型为整数 `int`, 此外我们使用 `check` 关键字定义了其取值范围 1 ~ 65535 +- `services` 的类型为 `Service` 列表类型,`Service`,并且我们用 `?` 标记了它是一个可选属性,这意味着我们可以不为其赋值。 +- `volumes` 的类型为 `Volume` 列表类型,并且我们用 `?` 标记了它是一个可选属性,这意味着我们可以不为其赋值。 + +### 2. 输出配置 + +我们可以使用如下命令行可以获得 `app` 实例的 YAML 输出 + +```shell +kcl main.k +``` + +输出为 + +```yaml +app: + domainType: Standard + containerPort: 80 + volumes: + - container: "*" + mountPath: /tmp + services: + - clusterIP: None + type: ClusterIP +``` + +## 小结 + +KCL 是一种用于定义配置和约束的语言,其核心功能是使用 schema 关键字进行建模,schema 允许定义具有属性、默认值、范围检查和其他约束的结构。使用 KCL schema 定义的结构可以用于验数据或生成代码。该文档演示了如何使用 schema 定义模型,使用 import 导入模型进行模块化管理,并使用 kcl 命令输出已定义结构实例的 YAML 配置。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/1-vault.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/1-vault.md new file mode 100644 index 000000000..f070a7841 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/1-vault.md @@ -0,0 +1,142 @@ +--- +id: vault +sidebar_label: Vault +--- + +# Vault + +## 简介 + +This guide will show you that KCL solves the secret management problem by integrating [Vault](https://developer.hashicorp.com/vault) and [Vals](https://github.com/helmfile/vals). + +## 先决条件 + +- Install [KCL](/docs/user_docs/getting-started/install) +- Prepare a [Kubernetes Cluster](https://kubernetes.io/) +- Install [Vault](https://developer.hashicorp.com/vault/downloads) +- Install [Vals](https://github.com/helmfile/vals) + +## 具体步骤 + +### 1. 获得示例 + +We put the application source code and infrastructure deployment code in different repos, which can be maintained by different roles to achieve the separation of concerns. + +- Get the application code + +```shell +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/secret-management/vault +``` + +- Show the config + +```shell +cat main.k +``` + +The output is + +```python +# Secret Management using Vault and Vals + +apiVersion = "apps/v1" +kind = "Deployment" +metadata = { + name = "nginx" + labels.app = "nginx" + annotations: { + "secret-store": "vault" + # Valid format: + # "ref+vault://PATH/TO/KV_BACKEND#/KEY" + "foo": "ref+vault://secret/foo#/foo" + "bar": "ref+vault://secret/bar#/bar" + } +} +spec = { + replicas = 3 + selector.matchLabels = metadata.labels + template.metadata.labels = metadata.labels + template.spec.containers = [ + { + name = metadata.name + image = "${metadata.name}:1.14.2" + ports = [{ containerPort = 80 }] + } + ] +} +``` + +The main.k file extends the configuration of the Nginx application and customizes annotations. Among them, the value of annotation `foo` and `bar` follow secret reference format (`ref+vault://PATH/TO/KV_BACKEND#/KEY`): + +- `ref+vault`: indicates that this is a secret reference, and the external storage service is `Vault`. +- `PATH/TO/KV_BACKEND`: specifies the path where a secret is stored. +- `KEY`: specifies the key to reading secret. + +The complete format is concatenated using a style similar to URI expressions, which can retrieve a secret stored externally. + +### 2. 预存敏感信息 + +Start the Vault Server + +```shell +vault server -dev +export VAULT_ADDR='http://127.0.0.1:8200' +# Note: Replace with your token +export VAULT_TOKEN=yourtoken +``` + +After Vault is started in development mode and unpacked, secrets are pre-stored, and the path and keys are consistent with `main.k`: + +```shell +vault kv put secret/foo foo=foo +vault kv put secret/bar bar=bar +``` + +### 3. 部署配置 + +Using the following command to apply the deployment manifest. + +```shell +kcl main.k | vals eval -f - | kubectl apply -f - +``` + +The expect output is + +```shell +deployment.apps/nginx created +``` + +### 4. 验证敏感信息 + +Next, verify that the secrets have been retrieved from Vault and replace the values of annotations of Nginx: + +- Verify the `foo` annotation + +```shell +kubectl get deploy nginx -o yaml | grep 'foo:' +``` + +The output is + +```yaml +foo: foo +``` + +- Verify the `bar` annotation + +```shell +kubectl get deploy nginx -o yaml | grep 'bar:' +``` + +The output is + +```yaml +bar: bar +``` + +So far, we have retrieved the secrets hosted in `Vault` and put them into use. + +## 小结 + +This guide introduces how KCL solves the secret management by integrating Vault and Vals. By following these steps, we can retrieve the secrets hosted in Vault and utilize them. diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/_category_.json new file mode 100644 index 000000000..c57bb30e2 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/secret-management/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Secret Management", + "position": 13 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/validation.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/validation.md new file mode 100644 index 000000000..d45e53059 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/validation.md @@ -0,0 +1,93 @@ +--- +title: "校验" +sidebar_position: 2 +--- + +## 简介 + +验证是校验数据是否准确、可靠并满足某些要求或限制的过程,包括检查数据的完整性、一致性、准确性和相关性。进行数据验证是为了确保数据符合其预期目的,并能有效使用。 + +我们可以使用 KCL 及其校验工具手动或自动进行数据验证,以确保数据的一致性。 + +## 使用 KCL 校验数据 + +除了使用 KCL 代码生成 JSON/YAML 等配置格式,KCL 还支持对 JSON/YAML 数据进行格式校验。作为一种配置语言,KCL 在验证方面几乎涵盖了 OpenAPI 的所有功能。在 KCL 中可以通过一个结构定义来约束配置数据,同时支持通过 check 块自定义约束规则,在 schema 中书写校验表达式对 schema 定义的属性进行校验和约束。通过 check 表达式可以非常清晰简单地校验输入的 JSON/YAML 是否满足相应的 schema 结构定义与 check 约束。 + +### 0. 先决条件 + +- 安装 [KCL](https://kcl-lang.io/docs/user_docs/getting-started/install) + +### 1. 获得示例 + +```shell +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/validation +``` + +我们可以执行如下命令显示配置 + +```bash +cat schema.k +``` + +输出为 + +```python +schema User: + name: str + age: int + message?: str + data: Data + labels: {str:} + hc: [int] + + check: + age > 10, "age must > 10" + +schema Data: + id: int + value: str +``` + +在 schema 中,我们可以使用 `check` 关键字来编写每个 schema 属性的验证规则。`check` 块中的每一行都对应于一个条件表达式。当满足条件时,验证成功。条件表达式后面可以跟 `, "报错信息"`,以指示检查失败时要给用户显示的消息。 + +综上所述,KCL Schema 中支持的校验类型为: + +| 校验类型 | 使用方法 | +| -------- | ---------------------------------------------------------- | +| 范围校验 | 使用 `<`, `>` 等比较运算符 | +| 正则校验 | 使用 `regex` 系统库中的 `match` 等方法 | +| 长度校验 | 使用 `len` 内置函数,可以求 `list/dict/str` 类型的变量长度 | +| 枚举校验 | 使用字面值联合类型 | +| 非空校验 | 使用 schema 的可选/必选属性 | +| 条件校验 | 使用 check if 条件表达式 | + +### 2. 验证数据 + +新建一个名为 `data.json` 的 JSON 配置文件: + +```json +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} +``` + +执行如下命令获得校验结果 + +```bash +kcl vet data.json schema.k +``` + +## 小结 + +KCL 是一种配置语言,通过其结构定义和用户定义的约束规则来支持数据验证。KCL Schema 中支持的验证类型包括范围、正则表达式、长度、枚举、可选/必需和条件。并且可以使用 KCL 验证工具或在此基础上构建的可视化产品来验证数据。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/0-overview.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/0-overview.md new file mode 100644 index 000000000..bc0d8138e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/0-overview.md @@ -0,0 +1,33 @@ +--- +title: "概述" +sidebar_position: 0 +--- + +import DocsCard from '@site/src/components/global/DocsCard'; +import DocsCards from '@site/src/components/global/DocsCards'; + +## Kubernetes + +[Kubernetes](https://kubernetes.io/) 是一个开源项目,用于在一组机器集群上运行和管理容器化应用程序。 + +[KCL](https://github.com/kcl-lang) 可以将 Kubernetes 资源 API 公开为跨常见云原生工具和应用程序的 KCL 代码模块。此外,可以使用 KCL 围绕这些 API 模块进行编程和配置、策略管理。 + +## 用例 + +- **动态配置策略管理**:使用现代语言(包括函数、类型、条件语句和丰富的 IDE 集成开发环境功能)来创建、编排、更改或验证应用负载的 Kubernetes API 资源,而不是使用 YAML、JSON、脚本和模板等方式。 +- **接入 Kubernetes 已有生态**:将 Kubernetes 配置清单和自定义资源类型转换为 KCL 配置和 Schema 并使用。 +- **Kubernetes 包管理**:使用 KCL 包管理工具从 Registry 下载安装和发布应用负载、容器和服务等模型。 + +## 文档 + + + +

将 Kubernetes 清单和 CRD 转换为 KCL 代码的指南。

+
+ +

使用 KCL 生成 Kubernetes 清单的指南。

+
+ +

提供一些云原生工具集成,以及使用 KCL 模块对 Kubernetes 清单进行变异或验证的指南。

+
+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/1-adapt-from-kubernetes.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/1-adapt-from-kubernetes.md new file mode 100644 index 000000000..f4536be6e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/1-adapt-from-kubernetes.md @@ -0,0 +1,194 @@ +--- +title: "从 Kubernetes 迁移或集成" +sidebar_position: 1 +--- + +## 简介 + +KCL 提供了许多对 Kubernetes 配置开箱即用的支持。通过 KCL 工具,我们首先可以将Kubernetes 配置清单和自定义类型集成到 KCL 中。本节将介绍如何从 Kubernetes 进行迁移和集成。 + +## 前置依赖 + +- 安装 [kcl](https://kcl-lang.io/docs/user_docs/getting-started/install/) + +## 快速开始 + +### 将 Kubernetes 配置清单转换为KCL + +首先,让我们获取示例。 + +```shell +git clone https://github.com/kcl-lang/kcl-lang.io.git/ +cd ./kcl-lang.io/examples/kubernetes/from-kubernetes +``` + +我们可以运行以下命令来显示配置。 + +```shell +cat deployment.yaml +``` + +输出结果为 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +将 Kubernetes YAML 代码转换为 KCL + +```shell +kcl import -f deployment.yaml +``` + +上述命令将生成文件 deployment.k + +```python +""" +This file was generated by the KCL auto-gen tool. DO NOT EDIT. +Editing this file might prove futile when you re-run the KCL auto-gen generate command. +""" + +apiVersion = "apps/v1" +kind = "Deployment" +metadata = { + name = "nginx-deployment" + labels = { + app = "nginx" + } +} +spec = { + replicas = 3 + selector = { + matchLabels = { + app = "nginx" + } + } + template = { + metadata = { + labels = { + app = "nginx" + } + } + spec = { + containers = [ + { + name = "nginx" + image = "nginx:1.14.2" + ports = [ + { + containerPort = 80 + } + ] + } + ] + } + } +} +``` + +我们可以运行以下命令来运行 KCL 代码并生成 YAML + +```shell +kcl deployment.k +``` + +输出结果为 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +### 从 Kubernetes 自定义资源生成 KCL 类型 + +KCL 支持从 Kubernetes OpenAPI/自定义资源定义(CRD)中提取和生成 KCL Schema。[KCL OpenAPI 规范](/docs/tools/cli/openapi/spec)定义了 OpenAPI 规范与 KCL 语言功能之间的映射关系。 + +如果您开发了 Kubernetes CRD,可以由 CRD 生成 KCL Schema,并基于此类型声明 CR。这里我们以 Kubernetes 文档中所示 [CronTab CRD](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#create-a-customresourcedefinition) 为例。 + +- 从 CRD 生成 KCL Schema + +```shell +# Convert the CRD YAML to KCL Schema +kcl import -m crd -s -f crd.yaml +# Init a new KCL project. +rm -rf kcl.mod && kcl mod init +# Add the crd models dependency +kcl mod add ./models --rename crd +``` + +- 使用生成的 KCL Schema 定义资源 + +```python +import crd.v1 + +v1.CronTab { + metadata.name = "my-new-cron-object", + spec: { + cronSpec = "* * * * */5", + image = "my-awesome-cron-image", + replicas = 3, + } +} +``` + +我们可以运行以下命令来运行 KCL 代码并生成 CR YAML + +```shell +kcl cr.k +``` + +输出结果为 + +```yaml +apiVersion: stable.example.com/v1 +kind: CronTab +metadata: + name: my-new-cron-object +spec: + cronSpec: "* * * * */5" + image: my-awesome-cron-image + replicas: 3 +``` + +## 小结 + +本节内容解释了如何使用 `kcl import` 工具将 Kubernetes YAML、CRD 等迁移到 KCL。快速入门指南将帮助您进行从 Kubernetes 的迁移或集成。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/2-generate-k8s-manifests.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/2-generate-k8s-manifests.md new file mode 100644 index 000000000..5b57c6604 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/2-generate-k8s-manifests.md @@ -0,0 +1,316 @@ +--- +title: "使用 KCL 生成并管理 Kubernetes 资源配置" +sidebar_position: 2 +--- + +## 简介 + +当我们管理 Kubernetes 资源清单时,我们常常会手写维护,或者使用 Helm 和 Kustomize 等工具来维护我们 YAML 配置或者配置模版,然后通过 kubectl 和 helm 命令行等工具将资源下发到集群。但是作为一个 "YAML 工程师" 每天维护 YAML 配置无疑是琐碎且无聊的,并且容易出错。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: ... # Omit +spec: + selector: + matchlabels: + cell: RZ00A + replicas: 2 + template: + metadata: ... # Omit + spec: + tolerations: + - effect: NoSchedules + key: is-over-quota + operator: Equal + value: 'true' + containers: + - name: test-app + image: images.example/app:v1 # Wrong ident + resources: + limits: + cpu: 2 # Wrong type. The type of cpu should be str + memory: 4Gi + # Field missing: ephemeral-storage + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: is-over-quota + operator: In + values: + - 'true' +``` + +- YAML 中的结构化数据是无类型的,缺乏验证方法,无法立即检查所有数据的有效性 +- YAML 编程能力欠佳,容易写出不正确的缩进,也没有逻辑判断等常见代码组织方式,容易写出大量重复配置,难以维护 +- Kubernetes 设计是复杂的,用户很难理解所有细节,比如上面配置中的 `toleration` 和 `affinity` 字段,如果用户不理解调度逻辑,它可能被错误地省略掉或者多余的添加 + +因此,KCL 期望在 Kubernetes YAML 资源管理解决如下问题: + +- 用**生产级高性能编程语言**以**编写代码**的方式提升配置的灵活度,比如条件语句、循环、函数、包管理等特性提升配置重用的能力 +- 在代码层面提升**配置语义验证**的能力,比如字段可选/必选、类型、范围等配置检查能力 +- 提供**配置分块编写、组合和抽象的能力**,比如结构定义、结构继承、约束定义等能力 + +## 先决条件 + +首先可以在 [KCL 快速开始](/docs/user_docs/getting-started/kcl-quick-start) 根据指导下载并安装 KCL,然后准备一个 [Kubernetes](https://kubernetes.io/) 环境 + +## 快速开始 + +### 1. 生成 Kubernetes 资源 + +我们可以编写如下 KCL 代码并命名为 main.k ,KCL 受 Python 启发,基础语法十分接近 Python, 比较容易学习和上手, 配置模式写法很简单,`k [: T] = v`, 其中 `k` 表示配置的属性名称; `v` 表示配置的属性值; `: T` 表示一个可选的类型注解。 + +```python +apiVersion = "apps/v1" +kind = "Deployment" +metadata = { + name = "nginx" + labels.app = "nginx" +} +spec = { + replicas = 3 + selector.matchLabels = metadata.labels + template.metadata.labels = metadata.labels + template.spec.containers = [ + { + name = metadata.name + image = "${metadata.name}:1.14.2" + ports = [{ containerPort = 80 }] + } + ] +} +``` + +上述 KCL 代码中我们分别声明了一个 Kubernetes Deployment 资源的 `apiVersion`、`kind`、`metadata` 和 `spec` 等变量,并分别赋值了相应的内容,特别地,我们将 `metadata.labels` 字段分别重用在 `spec.selector.matchLabels` 和 `spec.template.metadata.labels` 字段。可以看出,相比于 YAML,KCL 定义的数据结构更加紧凑,而且可以通过定义局部变量实现配置重用。 + +我们可以执行如下命令行得到一个 Kubernetes YAML 文件 + +```bash +kcl main.k +``` + +输出为: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +当然我们可以将 KCL 工具与 kubectl 等工具结合使用,让我们执行如下命令并看看效果 + +```shell +kcl main.k | kubectl apply -f - +``` + +输出为 + +```shell +deployment.apps/nginx-deployment configured +``` + +可以从命令行的结果看出与我们使用直接使用 YAML 配置和 kubectl apply 的一个 Deployment 体验完全一致 + +通过 kubectl 检查部署状态 + +```shell +kubectl get deploy +``` + +输出为 + +```shell +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-deployment 3/3 3 3 15s +``` + +### 2. 编写代码管理 Kubernetes 资源 + +对于 Kubernetes 资源发布时,我们常常会遇到配置参数需要动态指定的场景,比如不同的环境需要设置不同的 `image` 字段值生成不同环境的资源。对于这种场景,我们可以通过 KCL 的条件语句和 `option` 函数动态地接收外部参数。我们可以在上述例子的基础上根据不同的环境调整配置参数,比如对于如下代码,我们编写了一个条件语句并输入一个名为 `env` 的动态参数 + +```python +apiVersion = "apps/v1" +kind = "Deployment" +metadata = { + name = "nginx" + labels.app = "nginx" +} +spec = { + replicas = 3 + selector.matchLabels = metadata.labels + template.metadata.labels = metadata.labels + template.spec.containers = [ + { + name = metadata.name + image = "${metadata.name}:1.14.2" if option("env") == "prod" else "${metadata.name}:latest" + ports = [{ containerPort = 80 }] + } + ] +} +``` + +使用 KCL 命令行 `-D` 标记接收一个外部设置的动态参数: + +```bash +kcl main.k -D env=prod +``` + +输出为: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +上述代码片段中的 `image = metadata.name + ":1.14.2" if option("env") == "prod" else metadata.name + ":latest"` 意思为:当动态参数 `env` 的值被设置为 `prod` 时,image 字段值为 `nginx:1.14.2`, 否则为 `nginx:latest`,因此我们可以根据需要为 env 设置为不同的值获得不同内容的 Kubernetes 资源。 + +并且 KCL 支持将 option 函数动态参数维护在配置文件中,比如编写下面展示的 `kcl.yaml` 文件 + +```yaml +kcl_options: + - key: env + value: prod +``` + +使用如下命令行也可以得到同样的 YAML 输出,以简化 KCL 动态参数的输入过程 + +```bash +kcl main.k -Y kcl.yaml +``` + +输出为: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +### 3. 从 Registry 直接获取 Kubernetes 模块 + +KCL 开箱提供了所有版本(v1.14-v1.28)的 Kubernetes 模块,您可以通过在项目中执行`kcl mod add k8s:`来获取它。更多 Kubernetes 生态模块可以在[这里](https://artifacthub.io/packages/search?org=kcl&sort=relevance&page=1)找到。 + +```shell +kcl mod init my-module && cd my-module +kcl mod add k8s:1.28 +``` + +在 main.k 文件中编写 KCL 代码 + +```python +# Import and use the contents of the external dependency 'k8s'. +import k8s.api.apps.v1 as apps + +apps.Deployment { + metadata.name = "nginx-deployment" + metadata.labels.app = "nginx" + spec: { + replicas = 3 + selector.matchLabels = metadata.labels + template: { + metadata.labels = metadata.labels + spec.containers = [{ + name = metadata.labels.app + image = "nginx:1.14.2" + ports: [{ + containerPort = 80 + }] + }] + } + } +} +``` + +运行如下命令 + +```shell +kcl run +``` + +输出结果为 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.14.2 + name: nginx + ports: + - containerPort: 80 +``` + +## 小结 + +KCL 可以用于生成和管理 Kubernetes 资源,解决管理 YAML 配置的局限性,例如缺乏验证方法和较弱的编程能力等,并可以通过条件语句和 option 函数动态接收外部参数,从而能够根据不同的环境调整配置参数。此外,KCL 可以与 kubectl 等其他工具一起使用将配置一键生效到集群。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/1-kubectl-kcl-plugin.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/1-kubectl-kcl-plugin.md new file mode 100644 index 000000000..07d15737f --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/1-kubectl-kcl-plugin.md @@ -0,0 +1,207 @@ +--- +title: "Kubectl KCL 插件" +sidebar_position: 1 +--- + +## 简介 + +[Kubectl](https://kubernetes.io/docs/reference/kubectl/) is a command line tool for communicating with a Kubernetes cluster's control plane, using the Kubernetes API. You can use the `Kubectl-KCL-Plugin` to + +- Edit the YAML configuration in a hook way to separate data and logic for the Kubernetes manifests management. +- For multi-environment and multi-tenant scenarios, you can maintain these configurations gracefully rather than simply copy and paste. +- Validate all KRM resources using the KCL schema. + +## 前置条件 + +- Install [Kubectl](https://github.com/kubernetes/kubectl) +- Install [Kubectl KCL Plugin](https://github.com/kcl-lang/kubectl-kcl) + +## 快速开始 + +Let’s write a KCL function which add annotation `managed-by=krm-kcl` only to `Deployment` resources in the Kubernetes manifests. + +### Mutation + +#### 1. Get the Example + +```bash +git clone https://github.com/kcl-lang/kubectl-kcl.git/ +cd ./kubectl-kcl/examples/ +``` + +Show the config + +```shell +cat ./kcl-run-oci.yaml +``` + +The output is + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-annotation +spec: + params: + annotations: + managed-by: kubectl-kcl + source: oci://ghcr.io/kcl-lang/set-annotation +``` + +#### 2. Test and Run + +Run the KCL code via the `Kubectl KCL Plugin`. + +```bash +kubectl kcl run -f ./kcl-run-oci.yaml +``` + +The output yaml is + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + managed-by: kubectl-kcl + labels: + app: nginx + name: nginx-deployment +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:1.14.2 + name: nginx + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + managed-by: kubectl-kcl + name: test +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 9376 + selector: + app: MyApp +``` + +### Validation + +Let’s do a `https-only` validation for the `Ingress` resources in the Kubernetes manifests. + +#### 1. Get the Example + +Show the config + +```shell +cat ./kcl-vet-oci-err.yaml +``` + +The output is + +```yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: https-only +spec: + source: oci://ghcr.io/kcl-lang/https-only +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: tls-example-ingress +spec: + tls: + - hosts: + - https-example.foo.com + secretName: testsecret-tls + rules: + - host: https-example.foo.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: service1 + port: + number: 80 +``` + +#### 2. Test and Run + +Run the KCL code via the `Kubectl KCL Plugin`. + +```bash +kubectl kcl run -f ./kcl-vet-oci-err.yaml +``` + +The expected error message is + +```shell +Ingress should be https. The `kubernetes.io/ingress.allow-http: "false"` annotation is required for Ingress: tls-example-ingress +``` + +## Guides for Developing KCL + +Here's what you can do in the KCL code: + +- Read resources from `option("items")`. The `option("items")` complies with the [KRM Functions Specification](https://kpt.dev/book/05-developing-functions/01-functions-specification). +- Return a KRM list for output resources. +- Return an error using `assert {condition}, {error_message}`. +- Read the PATH variables. e.g. `option("PATH")`. +- Read the environment variables. e.g. `option("env")`. + +## More Resources + +- [Kubectl KCL Plugin](https://github.com/kcl-lang/kubectl-kcl) +- [Artifact Hub KCL Modules](https://artifacthub.io/packages/search?org=kcl&sort=relevance&page=1) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/2-helm-kcl-plugin.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/2-helm-kcl-plugin.md new file mode 100644 index 000000000..e822a499d --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/2-helm-kcl-plugin.md @@ -0,0 +1,100 @@ +--- +title: "Helm KCL 插件" +sidebar_position: 2 +--- + +## 简介 + +[Helm](https://github.com/helm/helm) 是一个管理 Charts 的工具。Charts 是预配置的 Kubernetes 资源的包。您可以使用 `Helm-KCL-Plugin` 来完成以下操作: + +- 以 hook 的方式编辑 Helm charts,将数据和逻辑分离以便更好地管理 Kubernetes manifests +- 对于多环境和多租户方案,可以优雅地维护这些配置,而不仅仅是简单地复制和粘贴 +- 使用 KCL 模式验证所有 KRM 资源 + +## 先决条件 + +- 安装 [Helm](https://github.com/helm/helm) +- 安装 [Helm KCL 插件](https://github.com/kcl-lang/helm-kcl) + +## 快速开始 + +让我们编写一个仅向 `Deployment` 资源添加 annotation `managed-by=helm-kcl-plugin` 的 KCL 函数 + +### 1. 获取示例 + +```bash +git clone https://github.com/kcl-lang/helm-kcl.git/ +cd ./helm-kcl/examples/workload-charts-with-kcl +``` + +### 2. 测试和运行 + +通过 `Helm KCL Plugin` 运行KCL代码。 + +```bash +helm kcl template --file ./kcl-run.yaml +``` + +输出的YAML为 + +```yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/instance: workload + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: workload + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: workload-0.1.0 + name: workload +spec: + ports: + - name: www + port: 80 + protocol: TCP + targetPort: 80 + selector: + app.kubernetes.io/instance: workload + app.kubernetes.io/name: workload + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/instance: workload + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: workload + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: workload-0.1.0 + name: workload + annotations: + managed-by: helm-kcl-plugin +spec: + selector: + matchLabels: + app.kubernetes.io/instance: workload + app.kubernetes.io/name: workload + template: + metadata: + labels: + app.kubernetes.io/instance: workload + app.kubernetes.io/name: workload + spec: + containers: + - image: nginx:alpine + name: frontend +``` + +## KCL 开发指南 + +以下是您可以在 KCL 代码中执行的操作: + +- 从 `option("resource_list")` 读取资源。`option("resource_list")` 符合 [KRM 函数规范](https://kpt.dev/book/05-developing-functions/01-functions-specification)。 你可以从 `option("resource_list")["items"]` 读取输入资源,并从 `option("resource_list")["functionConfig"]` 读取 `functionConfig`。 +- 返回输出资源的 KRM 列表。 +- 使用 `assert {condition},{error_message}` 返回错误消息。 + +## 更多文档和示例 + +- [Helm KCL 插件](https://github.com/kcl-lang/helm-kcl) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/3-kustomize-kcl-plugin.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/3-kustomize-kcl-plugin.md new file mode 100644 index 000000000..0a2173452 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/3-kustomize-kcl-plugin.md @@ -0,0 +1,104 @@ +--- +title: "Kustomize KCL 插件" +sidebar_position: 3 +--- + +## 简介 + +[Kustomize](https://github.com/kubernetes-sigs/kustomize) 允许自定义用于多种目的原始的、无模板的 YAML 文件,同时保留原始 YAML 不变和可用。 + +KCL 可用于创建函数,以改变和/或验证 Kubernetes 资源模型(KRM)的 YAML 输入/输出格式,并且我们提供 Kustomize KCL 函数来简化函数编写过程。 + +## 先决条件 + +- 安装 [kustomize](https://github.com/kubernetes-sigs/kustomize) + +## 快速开始 + +让我们编写一个仅向 Deployment 资源添加 annotation `managed-by=kustomize-kcl` 的 KCL 函数 + +### 1. 获取示例 + +```bash +git clone https://github.com/kcl-lang/kustomize-kcl.git +cd ./kustomize-kcl/examples/set-annotation/ +``` + +### 2. 测试和运行 + +```bash +kustomize fn run ./local-resource/ --dry-run +``` + +输出的YAML为 + +```yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-annotation + annotations: + config.kubernetes.io/function: | + container: + image: docker.io/kcllang/kustomize-kcl:v0.2.0 + config.kubernetes.io/path: example-use.yaml + internal.config.kubernetes.io/path: example-use.yaml +# EDIT THE SOURCE! +# This should be your KCL code which preloads the `ResourceList` to `option("resource_list") +spec: + source: | + [resource | {if resource.kind == "Deployment": metadata.annotations: {"managed-by" = "kustomize-kcl"}} for resource in option("resource_list").items] +--- +apiVersion: v1 +kind: Service +metadata: + name: test + annotations: + config.kubernetes.io/path: example-use.yaml + internal.config.kubernetes.io/path: example-use.yaml +spec: + selector: + app: MyApp + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx + annotations: + config.kubernetes.io/path: example-use.yaml + internal.config.kubernetes.io/path: example-use.yaml + managed-by: kustomize-kcl +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +## KCL 开发指南 + +以下是可以使用 KCL 执行的操作: + +- 从 `option("resource_list")` 读取资源。`option("resource_list")` 符合 [KRM 函数规范](https://kpt.dev/book/05-developing-functions/01-functions-specification)。 你可以从 `option("resource_list")["items"]` 读取输入资源,并从 `option("resource_list")["functionConfig"]` 读取 `functionConfig`。 +- 返回输出资源的 KRM 列表。 +- 使用 `assert {condition},{error_message}` 返回错误消息。 + +## 更多文档和示例 + +- [Kustomize KCL 插件](https://github.com/kcl-lang/kustomize-kcl) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/4-kpt-kcl-sdk.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/4-kpt-kcl-sdk.md new file mode 100644 index 000000000..1981ae3d0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/4-kpt-kcl-sdk.md @@ -0,0 +1,87 @@ +--- +title: "KPT KCL SDK" +sidebar_position: 4 +--- + +## 简介 + +[kpt](https://github.com/GoogleContainerTools/kpt) 是一个以包为中心的工具链,可实现配置原地编辑、自动化和交付,通过将声明性配置作为数据进行操作,从而简化 Kubernetes 平台和 KRM 驱动的基础设施(例如,Config Connector、Crossplane)的大规模管理,以实现 Kubernetes 配置编辑的自动化包括转换和验证。 + +KCL 可用于创建函数来转换和/或验证 YAML Kubernetes 资源模型 (KRM) 输入/输出格式,但我们提供 KPT KCL SDK 来简化函数编写过程。 + +## 先决条件 + +- 安装 [kpt](https://github.com/GoogleContainerTools/kpt) +- 安装 [Docker](https://www.docker.com/) + +## 快速开始 + +让我们编写一个仅向 Deployment 资源添加 annotation `managed-by=kpt` 的 KCL 函数 + +### 1. 获取示例 + +```bash +git clone https://github.com/kcl-lang/kpt-kcl-sdk.git/ +cd ./kpt-kcl-sdk/get-started/set-annotation +``` + +### 2. 显示 KRM + +```bash +kpt pkg tree +``` + +输出为 + +```bash +set-annotation +├── [kcl-fn-config.yaml] KCLRun set-annotation +└── data + ├── [resources.yaml] Deployment nginx-deployment + └── [resources.yaml] Service test +``` + +### 3. 显示和更新 KCL `FunctionConfig` + +```bash +cat ./kcl-fn-config.yaml +``` + +输出为 + +```yaml +# kcl-fn-config.yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: # kpt-merge: /set-annotation + name: set-annotation +spec: + # 编辑此源代码 + # 您在此的 KCL 代码将 `ResourceList` 预加载到 `option("resource_list")` + source: | + [resource | {if resource.kind == "Deployment": metadata.annotations: {"managed-by" = "kpt"}} for resource in option("resource_list").items] +``` + +### 4. 测试和运行 + +通过 kpt 运行 KCL 代码 + +```bash +kpt fn eval ./data -i docker.io/kcllang/kpt-kcl:v0.2.0 --fn-config kcl-fn-config.yaml + +# 验证 annotation 是否添加到 `Deployment` 资源并且其他资源 `Service` 没有这个 annotation。 +cat ./data/resources.yaml | grep annotations -A1 -B0 +``` + +输出为 + +```bash + annotations: + managed-by: kpt +``` + +可以看出,我们确实成功添加了 `managed-by=kpt` 标签 + +## 更多文档和示例 + +- [KPT KCL SDK](https://github.com/kcl-lang/kpt-kcl-sdk) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/_category_.json new file mode 100644 index 000000000..6e90c03cd --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/3-mutate-manifests/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Mutate or Validate Kubernetes Manifests", + "position": 3 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/4-publish-modules.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/4-publish-modules.md new file mode 100644 index 000000000..74c85b73b --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/4-publish-modules.md @@ -0,0 +1,91 @@ +--- +title: "发布 Kubernetes 模块" +sidebar_position: 4 +--- + +## 简介 + +社区官方的 KCL 模块 Registry 位于 [Artifact Hub](https://artifacthub.io/packages/search?org=kcl&sort=relevance&page=1),欢迎通过在 [GitHub 仓库](https://github.com/kcl-lang/artifacthub) 提交 pull requests 参与共建。本部分介绍如何发布 Kubernetes 模块并使用模块 Registry。 + +> 注意:如果您想将您的 KCL 模块发布到 `kcl-lang` 官方 Registry 中,则您的 KCL 模块的源代码将需要保存在上述存储库中。但是,KCL 允许接入三方的 Registry,例如各种 OCI Registry,如Docker Hub、Github Packages 和 Harbor 等。只需通过 `kcl registry login` 命令登录到对应的 Registry 即可。 + +> 注意:KCL 模块不会限制模块中配置或策略代码的具体内容。它可以是一个与 Kubernetes Helm Chart 类似的用于发布的应用程序工作负载配置,也可以是一段策略代码用于校验 Kubernetes 配置或者使用 CRD 转换而来的 KCL Schema。但是,我们强烈建议您在文档中提供有关 KCL 模块的简要介绍文档和具体用法。 + +## 先决条件 + +- 安装 [kcl](https://kcl-lang.io/docs/user_docs/getting-started/install/) + +## 快速入门 + +### 通过 GitHub PR 发布 KCL 模块 + +#### 1. Fork 并克隆代码存储库 + +```shell +git clone https://github.com/{your_github_id}/artifacthub --depth=1 +``` + +#### 2. 创建分支 + +我们建议您的分支名称为:`publish-pkg-`,`` 是您的 KCL 模块的称。以模块 helloworld 为例 + +进入您下载的 artifacthub 目录 + +```shell +cd artifacthub +``` + +为模块 `helloworld` 创建一个名为 `publish-pkg-helloworld` 的分支 + +```shell +git checkout -b publish-pkg-helloworld +``` + +#### 3. 添加您的 KCL 模块 + +在我们的示例中,使用 `kcl mod init` 命令创建模块 `helloworld` + +```shell +kcl mod init helloworld +``` + +您可以在模块的根目录添加一个 `README.md` 文件,以在 Artifact Hub 的模块主页上显示。 + +```shell +echo "## Introduction" >> helloworld/README.md +echo "This is a kcl module named helloworld." >> helloworld/README.md +``` + +为模块生成参考文档(可选) + +```shell +kcl doc generate +``` + +#### 4. 提交代码 + +您可以使用以下命令提交您的模块 + +使用 `git add .` 命令将您的模块添加到git的暂存区 + +```shell +git add . +``` + +使用 `git commit -s` 命令提交您的模块,我们建议您的提交消息遵循格式 `"publish module "`。 + +```shell +git commit -m "publish module helloworld" -s +``` + +提交分支 + +```shell +git push +``` + +#### 5. 提交 PR + +最后,您需要提交一个 PR 到存储库的主分支,包括您的分支 `publish-pkg-`。 + +- [如何创建 PR](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/_category_.json new file mode 100644 index 000000000..42681f2b0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Kubernetes", + "position": 9 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/index.md new file mode 100644 index 000000000..8d6340de1 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-k8s/index.md @@ -0,0 +1 @@ +# Kubernetes diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/1-overview.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/1-overview.md new file mode 100644 index 000000000..ae5c8b4b1 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/1-overview.md @@ -0,0 +1,47 @@ +--- +id: overview +sidebar_label: 概述 +--- + +import DocsCard from '@site/src/components/global/DocsCard'; +import DocsCards from '@site/src/components/global/DocsCards'; + +# Konfig 概述 + +在 KCL 中推荐通过**配置库**的方式统一管理所有的配置清单和模型库,即不仅存放抽象模型本身的 KCL 定义,还存放各种类型的配置清单,比如应用的运维配置、策略配置等。配置大库推荐托管在各类 VCS 系统中,以方便做配置的回滚和漂移检查。配置大库的最佳实践代号为 Konfig,仓库托管在 [Github](https://github.com/kcl-lang/konfig)。 + +⚡️ 配置大库主要包括: + +- KCL 模块声明文件(kcl.mod) +- KCL 领域模型库 (Kubernetes, Prometheus 等) +- 各类配置清单目录 (应用运维配置等) +- 配置构建和测试脚本 (Makefile,Github CI 文件等) + +之所以用一个统一的仓库管理全部的 KCL 配置代码,是由于不同代码包的研发主体不同,会引发出包管理和版本管理的问题。将业务配置代码、基础配置代码在一个统一仓库中,代码间的版本依赖管理会比较简单,通过定位唯一代码库的目录及文件即可,可以将配置代码统一管理,便于查找、修改、维护。 + +下面是配置大库(Konfig)的架构图: + +![](/img/docs/user_docs/guides/konfig/konfig-arch.png) + +Konfig 提供给用户开箱即用、高度抽象的配置界面,模型库最初朴素的出发点就是改善 YAML 用户的效率和体验,我们希望通过将代码更繁杂的模型抽象封装到统一的模型中,从而简化用户侧配置代码的编写。Konfig 由以下部分组成: + +- **核心模型**: + - **前端模型**:前端模型即「用户界面」,包含平台侧暴露给用户的所有可配置属性,其中省略了一些重复的、可推导的配置,抽象出必要属性暴露给用户,具有用户友好的特性,比如 server.k。 + - **后端模型**:后端模型是「模型实现」,是让前端模型属性生效的模型,主要包含前端模型实例的渲染逻辑,后端模型中可借助 KCL 编写校验和逻辑判断等以提高配置代码复用性和健壮性,对用户不感知,比如 server_backend.k +- **领域模型**:是不包含任何实现逻辑和抽象的模型,往往由工具转换生成,无需修改,和真正生效的 YAML 属性一一对应,底层模型需要经过进一步抽象,一般不直接被用户使用。比如,k8s 是 Kubernetes 场景的底层模型库。 + +此外,核心模型内部通过前端模型和后端模型两层抽象简化前端用户的配置代码,底层模型则是通过 KCL Import 工具自动生成。 + +## 文档 + + + +

Konfig 仓库目录和代码结构的说明。

+
+ +

使用 Konfig 的快速指南。

+
+ +

将新模型集成到 Konfig 以及 KCL 代码编写的最佳实践指南。

+
+
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/2-structure.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/2-structure.md new file mode 100644 index 000000000..5ada494e2 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/2-structure.md @@ -0,0 +1,37 @@ +--- +id: structure +sidebar_label: 工程结构 +--- + +# Konfig 工程结构 + +本文主要解释 Konfig 配置库的目录和代码结构 + +## 核心模型库结构 + +核心模型库命名为 `models`,主要包含前端模型、后端模型、Mixin、渲染器等,目录结构为: + +```bash +models +├── commons # 基础资源核心模型库 +├── kube # 云原生资源核心模型库 +│ ├── backend # 后端模型 +│ ├── frontend # 前端模型 +│ │ ├── common # 通用前端模型 +│ │ ├── configmap # ConfigMap 前端模型 +│ │ ├── container # 容器前端模型 +│ │ ├── ingress # Ingress 前端模型 +│ │ ├── resource # 资源规格前端模型 +│ │ ├── secret # Secret 前端模型 +│ │ ├── service # Service 前端模型 +│ │ ├── sidecar # Sidecar 容器前端模型 +│ │ ├── strategy # 策略前端模型 +│ │ ├── volume # Volume 前端模型 +│ │ └── server.k # 云原生应用运维前端模型 +│ ├── metadata # 应用运维的元数据模型 +│ ├── mixins # 统一放置可复用的 Mixin +│ ├── render # 渲染器,把前后端模型联系在一起的桥梁 +│ ├── templates # 静态配置 +│ └── utils # 工具方法 +└── metadata # 通用元数据模型 +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/3-quick-start.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/3-quick-start.md new file mode 100644 index 000000000..3fe1f40a4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/3-quick-start.md @@ -0,0 +1,230 @@ +--- +id: guide +sidebar_label: 快速开始 +--- + +# 简介 + +本篇指南向你展示,如何使用 KCL 语言与其相对应的 CLI 工具,完成一个运行在 Kubernetes 中的 Long-Running 应用的部署,我们将组织配置的单位叫做应用(Application),描述应用部署和运维细节的配置集合叫做应用服务(Server),它本质上是通过 KCL 定义的运维模型。 + +要将一个运行在 Kubernetes 中的应用完全部署起来,一般需要下发多个 Kubernetes 资源,本次演示的样例涉及以下 Kubernetes 资源: + +- 命名空间(Namespace) +- 无状态工作负载(Deployment) +- 服务(Service) + +> 不清楚相关概念的,可以前往 Kubernetes 官方网站,查看相关说明: + +- [Learn Kubernetes Basics](https://kubernetes.io/docs/tutorials/kubernetes-basics/) +- [Namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) +- [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) +- [Service](https://kubernetes.io/docs/concepts/services-networking/service/) + +## 准备工作 + +在开始之前,我们需要做以下准备工作: + +1. 安装 [kcl](https://kcl-lang.io/docs/user_docs/getting-started/install/) + +2. 下载开源 Konfig 库,仓库地址: [https://github.com/kcl-lang/konfig.git](https://github.com/kcl-lang/konfig.git) + +```shell +git clone https://github.com/kcl-lang/konfig.git && cd konfig +``` + +## 快速开始 + +### 1. 配置编译 + +Konfig 的编程语言是 KCL,不是 Kubernetes 认识的 JSON/YAML,因此还需要编译得到最终输出。 + +进入到项目的 Stack 目录(`examples/appops/nginx-example/dev`)并执行编译: + +```bash +cd examples/appops/nginx-example/dev && kcl run +``` + +可以获得如下 YAML 输出: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sampleappdev + namespace: sampleapp +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: dev + app.kubernetes.io/instance: sampleapp-dev + app.k8s.io/component: sampleappdev + template: + metadata: + labels: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: dev + app.kubernetes.io/instance: sampleapp-dev + app.k8s.io/component: sampleappdev + spec: + containers: + - env: + - name: MY_ENV + value: MY_VALUE + image: nginx:1.7.8 + name: main + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + requests: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + volumeMounts: [] +--- +apiVersion: v1 +kind: Namespace +metadata: + name: sampleapp +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + namespace: sampleapp +spec: + ports: + - nodePort: 30201 + port: 80 + targetPort: 80 + selector: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: dev + app.kubernetes.io/instance: sampleapp-dev + app.k8s.io/component: sampleappdev + type: NodePort +--- +apiVersion: v1 +kind: Namespace +metadata: + name: sampleapp +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + namespace: sampleapp +spec: + ports: + - nodePort: 30201 + port: 80 + targetPort: 80 + selector: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: prod + app.kubernetes.io/instance: sampleapp-prod + app.k8s.io/component: sampleappprod + type: NodePort +``` + +完成编译,可以看到 3 个资源: + +- 一个 name 为 `sampleappprod` 的 `Deployment` +- 一个 name 为 `sampleapp` 的 `Namespace` +- 一个 name 为 `nginx` 的 `Service` + +### 2. 配置修改 + +Server 模型中的 image 属性用于声明应用的业务容器镜像,我们可以修改 base/main.k 中的 image 的值进行镜像修改或升级: + +```diff +14c14 +< image = "nginx:1.7.8" +--- +> image = "nginx:latest" +``` + +重新编译配置代码可以获得修改后的 YAML 输出: + +```shell +kcl run -D env=dev +``` + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sampleappdev + namespace: sampleapp +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: dev + app.kubernetes.io/instance: sampleapp-dev + app.k8s.io/component: sampleappdev + template: + metadata: + labels: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: dev + app.kubernetes.io/instance: sampleapp-dev + app.k8s.io/component: sampleappdev + spec: + containers: + - env: + - name: MY_ENV + value: MY_VALUE + image: nginx:latest + name: main + ports: + - containerPort: 80 + protocol: TCP + resources: + limits: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + requests: + cpu: "100m" + memory: "100Mi" + ephemeral-storage: "1Gi" + volumeMounts: [] +--- +apiVersion: v1 +kind: Namespace +metadata: + name: sampleapp +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + namespace: sampleapp +spec: + ports: + - nodePort: 30201 + port: 80 + targetPort: 80 + selector: + app.kubernetes.io/name: sampleapp + app.kubernetes.io/env: dev + app.kubernetes.io/instance: sampleapp-dev + app.k8s.io/component: sampleappdev +``` + +## 资源 + +- 更多用例可以在[这里](https://github.com/kcl-lang/konfig/blob/main/examples/README.md)找到 +- 更多参考文档可以在[这里](https://github.com/kcl-lang/konfig/blob/main/docs/konfig.md)找到 + +## 小结 + +本文主要介绍了如何使用 KCL 语言与其相对应的 Konfig 库,完成一个运行在 Kubernetes 中的 Long-Running 服务应用的部署。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/4-best-practice.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/4-best-practice.md new file mode 100644 index 000000000..c4bf4b081 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/4-best-practice.md @@ -0,0 +1,271 @@ +--- +id: practice +sidebar_label: 最佳实践 +--- + +# 最佳实践 + +本文档旨在讲解新的业务模型接入 Konfig 大库以及 KCL 代码模型设计与编写的最佳实践,新业务模型一般采用前-后端模型分离的最佳实践进行设计与抽象,区分前端模型和后端模型的直接目的是将「用户界面」和「模型实现」进行分离,实现用户友好的简单的配置界面以及自动化配置增删改查接口。 + +## 工作流程 + +![](/img/docs/user_docs/guides/konfig/workflow.png) + +1. 首先使用 KCL OpenAPI 工具生成下游所需配置的 KCL 模型代码,对于 Kubernetes 模型;可以根据 CRD 或者 Swagger Model 生成,对于其他场景,可以使用 Terraform provider schema、Java Class 或者 Go Struct 生成相应 KCL Schema (建设中),作为后端模型并存放在 "基础配置代码" 中; +2. 使用 KCL 开发工具(包括 KCL 编译器、KCL format,doc,lint,test 等工具和 IDE 插件等),根据业务语义抽象前端模型; +3. 依据 Project & Stack 方式在 Konfig 仓库中组织用户侧配置代码(主要是对前端模型的实例化),Konfig 会自动根据 project.yaml 和 stack.yaml 文件进行测试; +4. 最后编译 KCL 代码生成 YAML,通过测试后,利用 CI/CD 流程完成配置的 diff 与分发。 + +## 模型结构 + +正如 web 应用会提供友好的用户界面,而在应用的后端对用户输入进行进一步推演得到最终落库的数据,类似地,使用 KCL 进行模型设计时同样遵循前后端分离的逻辑。此外当下游所需的数据内容发生变化时,我们仅需修改用户配置数据到后端模型的渲染/逻辑即可,从而避免了大规模修改用户配置的情况。以应用服务的 sidecar 配置为例,直接暴露给用户的只有 `user_sidecar_feature_gates`,而最终交给下游处理的数据中,则应是把 `user_sidecar_feature_gates` 作为 `sidecars` 配置的一部分包装起来的结果。比如如下代码: + +```python +# 用户可配的: +user_sidecar_feature_gates: str + +# 下游能处理的: +sidecars = [ + { + name = "sidecar_name" # sidecars 参数的额外模版参数,用户不需要进行配置 + feature_gates = user_sidecar_feature_gates + } +] +``` + +## Konfig 建模的一些最佳实践 + +### 使用一个属性代替配置模板 + +对于一些后端模型所需要填写的配置字段往往是大而全的设计,需要用户主动输入较为复杂的配置模版,并且不同用户对于该字段的填写内容基本一致,比如在下面示出的超卖逻辑的配置就需要用户填写大量的模板数据,心智成本较高。 + +对于此类常用复杂的模板一个简单的最佳实践是在前端模型中抽象为一个简单的 bool 类型的变量 overQuota,让用户做选择题而不是填空题,比如当 overQuota 变量为 True 时,后端模型才会渲染这个复杂逻辑。 + +- 前端模型属性 `overQuota` + +```python +overQuota: bool +``` + +- 后端模型 YAML 输出 + +```yaml +spec: + template: + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s/is-over-quota + operator: In + values: + - "true" +``` + +此外也可以根据具体的业务场景设计不同的模版名称来填空,比如如下所示的代码设计一个属性 template 来辅助用户做模版的选择而不是直接填入模板内容。合法的 template 值可以为 "success_ratio" 或者 "service_cost", 当后端模型扩展更多的模版时,前端代码无需作出任何修改,仅需在后端模型中适配相应模板逻辑即可。 + +```python +schema SLI: + template: str = "success_ratio" +``` + +此外,尽量不采用复杂的结构直接作为前端模型属性,避免用户使用该模型时需要借助过多的 KCL 语法特性(比如解包、循环等特性)或者书写很多临时变量完成该结构的实例化。 + +### 使用字面值类型和联合类型 + +在上述小节提到了可以使用一个字符串属性表示不同的模板名称,更进一步地是可以使用字面值类型表述 template 可选的内容,比如可以进行如下改进。 + +```python +schema SLI: + template: "success_ratio" | "service_cost" = "success_ratio" +``` + +其中 template 的类型为两个字符串类型的联合,表示 template 只能为 "success_ratio" 或者 "service_cost",当用户填写了其他字符串的值时,KCL 编译器会进行报错。 + +除了对字面值类型使用联合类型外,KCL 还支持对复杂类型如 schema 类型的联合。对于这种后端 oneof 配置的支持,KCL 内置了复合结构的联合类型进行支持。比如我们可以针对多种种场景定义自己的 SLI 前端类型:CustomSliDataSource,PQLSLIDataSource 和 StackSLIDataSource。 + +```python +schema CustomSLIDataSource: + customPluginUrl: str + +schema PQLSLIDataSource: + total?: str + error?: str + success?: str + cost?: str + count?: str + +schema StackSLIDataSource: + stack: str + groupBy?: str + metric?: str + +# Simplify type definitions using type aliases +type DataSource = CustomSLIDataSource | PQLSLIDataSource | StackSLIDataSource + +schema DataConfiguration: + sources: {str: DataSource} +``` + +这样前端模型设计的好处是编译器可以静态地检查出用户书写的类型只能是某一种类型,如果直接使用后端模型无法从模型上直接获得不同类型 type 与需要填写字段的映射关系。 + +此外,前端模型的整体设计上也应该考虑横向扩展性,尽可能地采用联合类型,充分利用代码化的优势,避免对接不同后端或者后端模型发生改变时带来不必要的大量代码前端代码与用户代码重构与修改。此外,对于其他 GPL 语言中常用的工厂模式,在 KCL 中也可以使用联合类型代替,比如想要根据某个字符串内容获得某个类型的构造函数,可以直接使用联合类型进行优化。 + +KCL 中书写工厂模式 + +```python +schema DataA: + id?: int = 1 + value?: str = "value" + +schema DataB: + name?: str = "DataB" + +_dataFactory: {str:} = { + DataA = DataA + DataB = DataB +} +dataA = _dataFactory["DataA"]() +dataB = _dataFactory["DataB"]() +``` + +使用联合类型替换工厂模式 + +```python +schema DataA: + id?: int = 1 + value?: str = "value" + +schema DataB: + name?: str = "DataB" + +# 直接使用联合类型即可 +dataA: DataA | DataB = DataA() +dataB: DataA | DataB = DataB() +``` + +### 列表/数组属性字典化 + +为了便于作配置的原地修改或者程序自动化查询修改,尽量将列表/数组属性定义为字典类型方便索引,因为在大部分配置场景对于复杂结构的列表类型,列表的索引 0, 1, 2, ..., n 不具备任何业务含义,列表中元素的顺序对该列表配置无任何影响,此时采用字典类型而不是列表类型更方便数据的查询与修改。首先以一个简单例子举例: + +```python +schema Person: + name: str + age: int + +schema House: + persons: [Person] + +house = House { + persons = [ + Person { + name = "Alice" + age = 18 + } + Person { + name = "Bob" + age = 10 + } + ] +} +``` + +比如在上述例子中,想要查询 name 为 "Alice" 的年龄 age, 就需要在 house.persons 这个列表中作遍历才能很查询到 Alice 的 age。而将 persons 定义为如下代码所示的字典,不仅从代码上看起来更加简洁,并且可以通过 house.persons.Alice.age 直接获得 Alice 的 age,并且整个配置的信息完整且无冗余信息。 + +```python +schema Person: + age: int + +schema House: + persons: {str: Person} # 将 persons 定义为字典而不是数组 + +house = House { + persons = { + Alice = Person { age = 18 } + Bob = Person { age = 10 } + } +} +``` + +### 为模型书写校验表达式 + +对于前端模型,往往需要对用户填写的字段进行校验,此时可以使用 KCL 的 check 表达式与 KCL 的内置函数/语法/系统库进行配合对字段进行校验。对于前端模型的校验尽可能直接书写在前端模型的定义中进行校验前置,避免错误传递到后端模型中发生意想不到的错误。 + +使用 all/any 表达式与 check 表达式进行校验 + +```python +import regex + +schema ConfigMap: + name: str + data: {str:str} + configMounts?: [ConfigMount] + + check: + all k in data { + regex.match(k, r"[A-Za-z0-9_.-]*") + }, "a valid config key must consist of alphanumeric characters, '-', '_' or '.'" + +schema ConfigMount: + containerName: str + mountPath: str + subPath?: str + + check: + ":" not in mountPath, "mount path must not contain ':'" +``` + +### 使用数值单位类型 + +KCL 中带单位的数字具有一个内置的类型 units.NumberMultiplier, 不允许进行任意四则运算。 + +```python +import units + +type NumberMultiplier = units.NumberMultiplier + +x0: NumberMultiplier = 1M # Ok +x1: NumberMultiplier = x0 # Ok +x2 = x0 + x1 # Error: unsupported operand type(s) for +: 'number_multiplier(1M)' and 'number_multiplier(1M)' +``` + +可以使用 `int()/float()` 函数和 `str()` 函数将数字单位类型转换为整数类型或者字符串类型,产生的字符串保留原有数字单位类型的单位。 + +```python +a: int = int(1Ki) # 1024 +b: str = str(1Mi) # "1Mi" +``` + +对于在 Konfig 中的 Kubernetes Resource 资源相关的定义均可使用数值单位类型进行书写 + +```python +import units + +type NumberMultiplier = units.NumberMultiplier + +schema Resource: + cpu?: NumberMultiplier | int = 1 + memory?: NumberMultiplier = 1024Mi + disk?: NumberMultiplier = 10Gi + epchygontee?: int +``` + +### 前端模型实例的自动化修改 + +在 KCL,可以通过命令行和 API 界面实现对前端模型实例的自动化修改,比如想要修改某个应用(Konfig Stack Path: appops/nginx-example/dev)配置的镜像内容,可以直接执行如下指令修改镜像 + +```python +kcl -Y kcl.yaml ci-test/settings.yaml -o ci-test/stdout.golden.yaml -d -O :appConfiguration.image=\"test-image-v1\" +``` + +更多与自动化相关的使用文档请参考 [自动化](/docs/user_docs/guides/automation) 一节 + +### 为模型添加代码注释 + +为便于用户理解以及模型文档自动生成,需要对定义的模型编写注释,注释内容一般包括模型的解释,模型字段的解释,类型,默认值,使用样例等。详细的 KCL Schema 代码注释编写规范以及模型文档自动生成可以参考 [KCL 文档规范](/docs/tools/cli/kcl/docgen) + +## 后端模型 + +后端模型是「模型实现」,主要包括将前端模型映射为后端模型的逻辑代码。当编写完成前端模型后,我们可以使用前端模型 Schema 新建前端模型的实例 instance 并编写相应的后端映射/渲染代码将这些前端 instance 转换为后端模型,并且利用 KCL 多文件编译和 `Schema.instances()` 函数可以做到前端代码和后端代码的高度解耦,用户仅需关心前端的配置而不感知模型复杂的校验、逻辑判断等代码。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/_category_.json new file mode 100644 index 000000000..a71426f9e --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-konfig/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Konfig", + "position": 10 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/_category_.json new file mode 100644 index 000000000..05f8004f9 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "KubeVela", + "position": 16 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/index.md new file mode 100644 index 000000000..4b14aa89c --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kubevela/index.md @@ -0,0 +1,99 @@ +# KubeVela + +[KubeVela](https://kubevela.net/) 是一个 CNCF 基金会托管的现代的应用交付系统,它基于 Open Application Model(OAM)规范构建,旨在屏蔽 Kubernetes 的复杂性,提供一套简单易用的命令行工具和 APIs,让开发者无需关心底层细节即可部署和运维云原生应用。 + +将 KCL 与 KubeVela 一起使用具有如下好处: + +- **更简单的配置**:在客户端层面为 KubeVela OAM 配置提供更强的模版化能力如条件,循环等,减少样板 YAML 书写,同时复用 KCL 模型库和工具链生态,提升配置及策略编写的体验和管理效率。 +- **更好的可维护性**:通过 KCL 可以提供更有利于版本控制和团队协作的配置文件结构,而不是围绕 YAML 进行配置,同时搭配 KCL 编写的 OAM 应用模型,可以使得应用配置更易于维护和迭代。 +- **更简化的操作**:结合 KCL 的配置简洁性和 KubeVela 的易用性,可以简化日常的操作任务,比如部署更新、扩展或回滚应用。开发者可以更加专注于应用本身,而不是部署过程中的繁琐细节。 +- **更好的跨团队协作**:通过 KCL 配置分块编写以及包管理能力与 KubeVela 结合使用,可以定义更清晰的界限,使得不同的团队(如开发、测试和运维团队)可以有条理地协作。每个团队可以专注于其职责范围内的任务,分别交付、分享和复用各自的配置,而不用担心其他方面的细节。 + +## 快速开始 + +### 1. 配置 Kubernetes 集群 + +- 安装 [K3d](https://github.com/k3d-io/k3d) 并创建一个集群 + +```bash +k3d cluster create +``` + +> 注意:你可以在此方案中使用其他方式创建您自己的 Kubernetes 集群,如 kind, minikube 等。 + +### 2. 安装 KubeVela + +- 安装 KubeVela CLI + +```bash +curl -fsSl https://kubevela.net/script/install.sh | bash +``` + +- 安装 KubeVela Core + +```bash +vela install +``` + +### 3. 安装 KCL 并编写配置 + +- 安装 KCL + +```bash +curl -fsSL https://kcl-lang.io/script/install-cli.sh | /bin/bash +``` + +- 新建工程并添加 OAM 依赖 + +```shell +kcl mod init kcl-play-svc && cd kcl-play-svc && kcl mod add oam +``` + +- 在 main.k 中编写如下代码 + +```python +import oam + +oam.Application { + metadata.name = "kcl-play-svc" + spec.components = [{ + name = metadata.name + type = "webservice" + properties = { + image = "kcllang/kcl:v0.9.0" + ports = [{port = 80, expose = True}] + cmd = ["kcl", "play"] + } + }] +} +``` + +> 注意,你可以在 ArtifactHub 上查阅到相应的 OAM 模型文档或者直接在 IDE 中查看 [https://artifacthub.io/packages/kcl/kcl-module/oam](https://artifacthub.io/packages/kcl/kcl-module/oam) or in the IDE extension. + +![oam-definition-hover](/img/blog/2023-12-15-kubevela-integration/oam-definition-hover.png) + +### 4. 部署应用并验证 + +- 下发配置 + +```shell +kcl run | vela up -f - +``` + +- 端口转发 + +```shell +vela port-forward kcl-play-svc +``` + +然后我们可以在浏览器中看到 KCL Playground 应用成功运行 + +![kcl-play-svc](/img/blog/2023-12-15-kubevela-integration/kcl-play-svc.png) + +## 结论 + +通过本篇文档的教程,我们可以使用 KubeVela 和 KCL 等初步部署云原生应用,未来我们将补充更多文档讲解如何在客户端使用 KCL 进一步扩展 KubeVela 的能力 + +- 使用 KCL 的继承、组合和校验手段扩展 OAM 模型,比如根据您的基础设施或者组织基于 OAM 定义更适合的应用抽象模型 +- 使用 KCL 配置分块编写,条件,逻辑,循环和模块化能力更好地组织 OAM 多环境配置,提升模版化能力,比如将较长的 App Definition 分散到不同的文件进行组织,减少样板配置 +- 与 KusionStack 和 ArgoCD 等项目进一步集成实现更好的 GitOps diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/_category_.json new file mode 100644 index 000000000..9f9144987 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "KusionStack", + "position": 15 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/index.md new file mode 100644 index 000000000..2906ab830 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/guides/working-with-kusion/index.md @@ -0,0 +1,15 @@ +# KusionStack + +**KusionStack 是开源的云原生可编程技术栈!** + +KusionStack 是一个可编程、高灵活性的应用交付及运维技术栈,灵感源于融合(Fusion)一词,旨在帮助企业构建的应用运维配置管理平面及 DevOps 生态。 + +1. 融合**专有云**,**混合云**,**多云**混合场景 +2. 融合以**云原生技术**为主,同时采用**多种平台技术**的混合平台技术选型 +3. 融合**多项目**、**多团队**、**多角色**、**多租户**、**多环境**的企业级诉求 + +基于 Platform as Code (平台服务即代码)理念,研发者可以快速收敛围绕**应用运维生命周期**的全量配置定义,面向**混合技术体系及云环境**,完成从应用运维研发到上线的**端到端工作流程**,真正做到**一处编写,随处交付**。 + +![](/img/docs/user_docs/intro/kusion-stack-1.png) + +更多文档请参考: [https://kusionstack.io/](https://kusionstack.io/) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/_category_.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/_category_.json new file mode 100644 index 000000000..d670513b4 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "常见问答", + "position": 6 +} diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-cli.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-cli.md new file mode 100644 index 000000000..035c021c8 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-cli.md @@ -0,0 +1,107 @@ +--- +sidebar_position: 4 +--- + +# 命令行工具 + +## 1. Konfig 大库应用目录下的 settings.yaml 文件的作用是什么? + +KCL 中 settings.yaml 文件表示 KCL 命令行工具的配置参数文件,可以将编译的配置放入其中进行调用比如需要编译的文件,需要输入的 option 动态参数 `-d`,是否需要忽略掉空值 None `-n` 等配置。 + +比如对于如下的命令行运行参数 + +```shell +kcl main.k -D key=value -n -r +``` + +就可以使用如下的命令行参数和 settings.yaml 配置文件代替 + +```shell +kcl -Y settings.yaml +``` + +settings.yaml + +```yaml +kcl_cli_configs: + files: + - main.k + disable_none: true + strict_range_check: true +kcl_options: + - key: key + value: value +``` + +- `kcl_cli_configs` 表示可以配置的编译参数,`file` 用于配置编译的 KCL 文件,`disable_none` 表示是否使用 `-n` 参数,`strict_range_check` 表示是否使用 `-r` 参数。 +- `kcl_options` 表示可以配置的动态参数,`key` 表示动态参数的名称,`value` 表示动态参数的值 + +注意:settings.yaml 的文件名称可替换,只要其中的配置结构满足规定即可 + +## 2. 如何传入动态参数?如何在代码中获取命令行传入的动态参数? + +KCL 支持多种方式传入动态参数 + +- `-D`: 使用 KCL 命令行的-D 参数可以直接传入动态参数,支持基本数据类型 str/int/float/bool, 以及结构数据类型 list/dict + +```shell +kcl main.k -D env-type=TEST -D deploy-topology='[{"cluster":"my-cluster","idc":"my-idc","replicas":2,"workspace":"my-idc","zone":"my-zone"}]' +``` + +- `-Y`: 使用 KCL 命令行的-Y 参数可以间接通过配置文件传入动态参数: + +```yaml +kcl_options: + - key: env-type + value: TEST + - key: deploy-topology + value: + - cluster: my-cluster + idc: my-idc + replicas: 2 + workspace: my-workspace + zone: my-zone +``` + +在代码中使用内置的 option 函数获取即可 + +```python +env = option("env-type") +deploy_topology = option("deploy-topology") +``` + +输出 YAML + +```yaml +env: TEST +deploy_topology: + - cluster: my-cluster + idc: my-idc + replicas: 2 + workspace: my-workspace + zone: my-zone +``` + +## 3. 如何使用 kcl 的多文件编译特性? + +- 使用 KCL 命令行工具直接书写多文件编译 + +```shell +kcl file1.k file2.k file3.k +``` + +- 在配置文件中配置并配合 KCL 命令行工具参数 `-Y` 使用 + +settings.yaml + +```yaml +kcl_cli_configs: + files: + - file1.k + - file2.k + - file3.k +``` + +```shell +kcl -Y settings.yaml +``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-install.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-install.md new file mode 100644 index 000000000..00bcf6ff0 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-install.md @@ -0,0 +1,56 @@ +--- +sidebar_position: 5 +--- + +# 安装问题 + +## MacOS 提示无法打开 "kcl",因为 Apple 无法检查其是否包含恶意软件 + +MacOS 提示无法打开 "kcl",因为 Apple 无法检查其是否包含恶意软件。这个错误是因为 macOS 操作系统中的 Gatekeeper 安全功能阻止了应用程序的运行。要解决此问题,请按照以下步骤操作: + +打开"系统偏好设置"并点击"安全性与隐私"。 在"通用"选项卡中,您将看到一个消息:"kcl" 已被阻止。单击"仍要打开"。 或者,你可以单击"打开任何方式"以打开你的应用程序。(可能需要使用管理员权限来打开应用程序。) + +如果不想在每次打开应用程序时都执行这些步骤,则可以的应用程序添加到白名单中,以便在不受阻止的情况下运行。要将您的应用程序添加到白名单中,请执行以下操作: + +打开终端并输入以下命令: + +```shell +xattr -d com.apple.quarantine /path/to/kcl +``` + +其中,/path/to/kcl 是 kcl 应用程序的完整路径。运行命令后,应用程序将被添加到白名单中,Gatekeeper 将不再阻止其运行。 + +## 在 Windows/Linux/MacOS 平台上报 program not found 或者 run linker failed 错误 + +请确保如下依赖在您的 PATH 中 + +- MacOS: `clang` +- Linux: `gcc` +- Windows: `cl.exe` (可以通过安装 `MSVC` 获得,主要包括 `MSVCP140.dll` 和 `VCRUNTIME140.dll` 等程序集) + +## 错误:invalid character 'c' looking for beginning of value + +请确保如下依赖在您的 PATH 中 + +- MacOS: `clang` +- Linux: `gcc` +- Windows: `cl.exe` (可以通过安装 `MSVC` 获得,主要包括 `MSVCP140.dll` 和 `VCRUNTIME140.dll` 等程序集) + +## 在 Windows 平台上遇到 exit status 0xc0000135 错误 + +请确保您的 Windows 上安装了 `.NET Framework` 和 `MSVC`,如没有安装,可以安装并重试。 + +## 在容器中启动/运行 KCL 报没有权限或者找不到文件的错误 + +这是因为 KCL 在编译时的默认全局配置和全局包缓存需要写入权限,一种解决方式是将全局配置和包目录设置到 `/tmp` 文件夹,详见[这里](https://github.com/kcl-lang/cli/blob/main/Dockerfile) 的 Dockerfile 配置 + +```dockerfile +ENV KCL_PKG_PATH=/tmp +ENV KCL_CACHE_PATH=/tmp +``` + +## 在 MacOS 出现错误 docker-credential-desktop: executable file not found in $PATH + +KCL 的包管理工具底层借助 docker 提供的三方库完成与 OCI Registry 的交互,会产生配置文件 ~/.docker/config.json,这个错误通常发生在从 Docker Desktop 切换到 Podman,而本地没有安装 Docker 的情况下。该文件会被用于在对 BuildKit 进行身份验证的调用中读取。要解决此问题,请尝试删除或重命名 ~/.docker/config.json 文件。 + +更多关于该错误的详细信息: diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-kcl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-kcl.md new file mode 100644 index 000000000..9d050af63 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-kcl.md @@ -0,0 +1,2681 @@ +--- +sidebar_position: 2 +--- + +# KCL 语法 + +## 1. 如何用 KCL 写一个简单的 key-value 对配置 + +创建一个名为 `config.k` 的文件 + +```python +cpu = 256 +memory = 512 +image = "nginx:1.14.2" +service = "my-service" +``` + +上述 KCL 代码中,定义了 4 个变量 `cpu` 和 `memory` 被声明为整数类型,并且它们的值分别为 `256` 和 `512`,而 `image` 和 `service` 是字符串类型,它们的值分别为 `image` 和 `service` + +使用如下命令可以将上述 KCL 文件编译为 YAML 进行输出 + +``` +kcl config.k +``` + +得到的 YAML 输出为: + +```yaml +cpu: 256 +memory: 512 +image: nginx:1.14.2 +service: my-service +``` + +如果想要输出到文件,可以使用 `-o|--output` 参数: + +``` +kcl config.k -o config.yaml +``` + +## 2. KCL 中有哪些基本的数据类型? + +KCL 目前的基本数值类型和值包含: + +- 整数类型 `int` + - 举例: 十进制正整数 `1`, 十进制负整数 `-1`, 十六进制整数 `0x10`, 八进制整数 `0o10`, 二进制整数 `0b10` +- 浮点数类型 `float` + - 举例: 正浮点数 `1.10`, `1.0`, 负浮点数 `-35.59`, `-90.`, 科学记数法浮点数 `32.3e+18`, `70.2E-12` +- 布尔类型 `bool` + - 举例: 真值 `True`, 假值 `False` +- 字符串类型 `str` - 使用引号 `'`, `"` 标记 + - 举例: 双引号字符串 `"string"`, `"""string"""`, 单引号字符串 `'string'`, `'''string'''` +- 列表类型 `list` - 使用 `[`, `]` 标记 + - 举例: 空列表 `[]`, 字符串列表 `["string1", "string2", "string3"]` +- 字典类型 `dict` - 使用 `{`, `}` 标记 + - 举例: 空字典 `{}`, 键值均为字符串类型的字典 `{"key1": "value1", "key2": "value2"}` +- 结构类型 `schema` - 使用关键字 `schema` 定义,并使用相应的 schema 名称进行实例化 +- 空值类型 `None` - 用于表示一个变量的值为空,与输出 YAML 的 `null` 值对应 +- 未定义值类型 `Undefined` - 用于表示一个变量未被赋值,值为 `Undefined` 的变量不会被输出到 YAML 中 + +```python +schema Person: + name: str + age: int + +alice = Person { + name = "Alice" + age = 18 +} +bob = Person { + name = "Bob" + age = 10 +} +``` + +注意: 所有 KCL 类型的变量均可赋值为空值 `None` 和未定义的值 `Undefined` + +## 3. 有些 KCL 变量名带 `_` 下划线前缀表示什么?和不带 `_` 下划线前缀的区别是什么?分别适合什么场景下使用? + +KCL 中带下划线前缀的变量表示一个**隐藏**的,**可变**的变量,**隐藏**表示带下划线前缀的变量不会被输出到 YAML 当中,包括包级别的下划线前缀变量和 schema 当中的下划线前缀变量。**可变**表示带下划线前缀的变量可被多次重复赋值,不带下划线前缀的变量被赋值后不可变。 + +带 `_` 下划线前缀的变量与不带 `_` 下划线前缀变量的区别是: 不带 `_` 下划线前缀变量默认是导出到 YAML 当中的,并且具有强不可变性;带 `_` 下划线前缀变量是不导出的,可变的。 + +```python +name = 'Foo' # 导出变量,不可变变量 +name = 'Bar' # 错误:导出变量只能设置一次 +``` + +```python +_name = 'Foo' # 隐藏变量,可变变量 +_name = 'Bar' + +schema Person: + _name: str # hidden and mutable +``` + +## 4. 如何向 dict 中添加元素? + +可以使用 union 运算符 `|`, 或者 dict 解包运算符 `**` 来向 dict 中添加一个元素,并且可以使用 `in`,`not in` 等关键字判断 dict 变量当中是否包含某一个键值 + +```python +_left = {key: {key1 = "value1"}, intKey = 1} # 注意使用 = 表示覆盖 +_right = {key: {key2 = "value2"}, intKey = 2} +dataUnion = _left | _right # {"key": {"key1": "value1", "key2": "value2"}, "intKey": 2} +dataUnpack = {**_left, **_right} # {"key": {"key1": "value1", "key2": "value2"}, "intKey": 2} +``` + +输出 YAML 为: + +```yaml +dataUnion: + key: + key1: value1 + key2: value2 + intKey: 2 +dataUnpack: + key: + key1: value1 + key2: value2 + intKey: 2 +``` + +此外还可以使用 `字符串插值` 或者字符串 `format` 成员函数特性向 kcl dict 添加变量键值对 + +```python +dictKey1 = "key1" +dictKey2 = "key2" +data = { + "${dictKey1}" = "value1" + "{}".format(dictKey2) = "value2" +} +``` + +输出 YAML 为: + +```yaml +dictKey1: key1 +dictKey2: key2 +data: + key1: value1 + key2: value2 +``` + +## 5. 如何修改 dict 中的元素? + +我们可以使用 union 运算符 `|`, 或者解包运算符 `**` 修改 dict 当中的元素 + +```python +_data = {key = "value"} # {"key": "value"} +_data = _data | {key = "override_value1"} # {"key": "override_value1"} +_data = {**_data, **{key = "override_value2"}} # {"key": "override_value2"} +``` + +如果想要删除 dict 中某个键为 `key` 的值,可以使用解包运算符 `**{key = Undefined}` 或者合并运算符 `| {key = Undefined}` 进行覆盖,覆盖后 key 的值为 Undefined,不会进行 YAML 输出。 + +## 6. 如何向 list 中添加元素? + +在 list 中添加元素有两种方式: + +- 使用 `+`, `+=` 和 slice 切片连接组装 list 变量达到向 list 中添加元素的目的 + +```python +_args = ["a", "b", "c"] +_args += ["end"] # 在list尾部添加元素"end", ["a", "b", "c", "end"] +_args = _args[:2] + ["x"] + _args[2:] # 在list索引为2的地方插入元素"x", ["a", "b", "x", "c", "end"] +_args = ["start"] + _args # 在list头部添加元素"start", ["start", "a", "b", "x", "c", "end"] +``` + +- 使用 `*` 解包运算符连接合并 list + +```python +_args = ["a", "b", "c"] +_args = [*_args, "end"] # 在list尾部添加元素"end", ["a", "b", "c", "end"] +_args = ["start", *_args] # 在list头部添加元素"start", ["start", "a", "b", "c", "end"] +``` + +注意:当接连的变量为 `None/Undefined` 时,使用 `+` 可能会发生错误,这时使用 list 解包运算符 `*` 或者使用 `or` 运算符取 list 的默认值可以避免空值判断 + +```python +data1 = [1, 2, 3] +data2 = None +data3 = [*data1, *data2] # Right [1, 2, 3] +data4 = data1 + data2 or [] # Right [1, 2, 3], 使用 or 取 data2 的默认值为 [], 当 data2 为 None/Undefined 时,取空列表 [] 进行计算 +data5 = data1 + data2 # Error: can only concatenate list (not "NoneType") to list +``` + +## 7. 如何修改/删除 list 中的元素? + +修改 list 中的元素分为两种方式: + +- 直接修改 list 某个索引处的值,使用 slice 切片 + +```python +_index = 1 +_args = ["a", "b", "c"] +_args = _args[:index] + ["x"] + _args[index+1:] # 修改list索引为1的元素为"x", ["a", "x", "c"] +``` + +- 根据某个条件修改 list 当中的元素,使用 list comprehension 列表推导式 + +```python +_args = ["a", "b", "c"] +_args = ["x" if a == "b" else a for a in _args] # 将list当中值为"b"的值都修改为"x", ["a", "x", "c"] +``` + +删除 list 中的元素分为两种方式: + +- 使用 list for 推导表达式中 if 过滤条件 +- 使用 filter 表达式对 list 进行元素过滤 + +比如想要删除一个列表 `[1, 2, 3, 4, 5]` 中大于 2 的数字,则在 KCL 中可以写为: + +```python +originList = [1, 2, 3, 4, 5] +oneWayDeleteListItem = [item for item in originList if item <= 2] +anotherWayDeleteListItem = filter item in originList { + item <= 2 +} +``` + +输出如下结果 + +```yaml +originList: + - 1 + - 2 + - 3 + - 4 + - 5 +oneWayDeleteListItem: + - 1 + - 2 +anotherWayDeleteListItem: + - 1 + - 2 +``` + +## 8. 怎样写 for 循环?怎样理解和使用 list comprehension 列表推导式 和 dict comprehension 字典推导式 ? + +KCL 目前仅支持函数式/声明式的推导式 for 循环方式,可以按照如下方式遍历 dict 和 list 变量: + +list 推导式具体形式为(其中推导式两边使用方括号 `[]`): + +```txt +[expression for expr in sequence1 + if condition1 + for expr2 in sequence2 + if condition2 + for expr3 in sequence3 ... + if condition3 + for exprN in sequenceN + if conditionN] +``` + +dict 推导式具体形式为(其中推导式两边使用花括号 `{}`): + +```txt +{expression for expr in sequence1 + if condition1 + for expr2 in sequence2 + if condition2 + for expr3 in sequence3 ... + if condition3 + for exprN in sequenceN + if conditionN} +``` + +上述推导式中的 `if` 表示过滤条件,满足条件的表达式 `expr` 才会生成到新的 list 或 dict 中 + +list 推导式举例: + +```python +_listData = [1, 2, 3, 4, 5, 6] +_listData = [l * 2 for l in _listData] # _listData中所有元素都乘以2,[2, 4, 6, 8, 10, 12] +_listData = [l for l in _listData if l % 4 == 0] # 筛选出_listData中可以被4整除的所有元素,[4, 8, 12] +_listData = [l + 100 if l % 8 == 0 else l for l in _listData] # 遍历_listData, 当其中的元素可以被8整除时,将该元素加100,否则保持不变, [4, 108, 12] +``` + +注意上述代码中第 3 行和第 4 行两个 `if` 的区别: + +- 第一个 `if` 表示 list 变量 `_listData` 本身的推导式过滤条件,后不能跟 `else`,满足该过滤条件的元素会继续放在该列表中,不满足条件的元素被剔除,有可能会使列表长度发生变化 +- 第二个 `if` 表示 list 迭代变量 `l` 的选择条件,表示 `if-else` 三元表达式,后必须跟 `else`,不论是否满足该条件,产生的元素仍然在该列表中,列表长度不变 + +dict 推导式举例: + +```python +_dictData = {key1 = "value1", key2 = "value2"} +_dictData = {k = _dictData[k] for k in _dictData if k == "key1" and _dictData[k] == "value1"} # 将_dictData中key为"key1", value为"value1"的元素筛选出来, {"key1": "value1"} +``` + +使用推导式获得 dict 所有 key: + +```python +dictData = {key1 = "value1", key2 = "value2"} +dictDataKeys = [k for k in _dictData] # ["key1", "key2"] +``` + +使用推导式对 dict 按照 key 的字典序升序进行排序: + +```python +dictData = {key3 = "value3", key2 = "value2", key1 = "value1"} # {'key3': 'value3', 'key2': 'value2', 'key1': 'value1'} +dictSortedData = {k = dictData[k] for k in sorted(dictData)} # {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'} +``` + +多级推导式举例: + +```python +array1 = [1, 2, 3] +array2 = [4, 5, 6] +data = [a1 + a2 for a1 in array1 for a2 in array2] # [5, 6, 7, 6, 7, 8, 7, 8, 9] len(data) == len(array1) * len(array2) +``` + +双变量循环(for 推导表达式支持 list 的索引迭代以及 dict 的 value 迭代,可以简化 list/dict 迭代过程代码书写): + +- list + +```python +data = [1000, 2000, 3000] +# 单变量循环 +dataLoop1 = [i * 2 for i in data] # [2000, 4000, 6000] +dataLoop2 = [i for i in data if i == 2000] # [2000] +dataLoop3 = [i if i > 2 else i + 1 for i in data] # [1000, 2000, 3000] +# 双变量循环 +dataLoop4 = [i + v for i, v in data] # [1000, 2001, 3002] +dataLoop5 = [v for i, v in data if v == 2000] # [2000] +# 使用_忽略循环变量 +dataLoop6 = [v if v > 2000 else v + i for i, v in data] # [1000, 2001, 3000] +dataLoop7 = [i for i, _ in data] # [0, 1, 2] +dataLoop8 = [v for _, v in data if v == 2000] # [2000] +``` + +- dict + +```python +data = {key1 = "value1", key2 = "value2"} +# 单变量循环 +dataKeys1 = [k for k in data] # ["key1", "key2"] +dataValues1 = [data[k] for k in data] # ["value1", "value2"] +# 双变量循环 +dataKeys2 = [k for k, v in data] # ["key1", "key2"] +dataValues2 = [v for k, v in data] # ["value1", "value2"] +dataFilter = {k = v for k, v in data if k == "key1" and v == "value1"} # {"key1": "value1"} +# 使用_忽略循环变量 +dataKeys3 = [k for k, _ in data] # ["key1", "key2"] +dataValues3 = [v for _, v in data] # ["value1", "value2"] +``` + +## 9. 怎样写 if 条件语句? + +KCL 支持两种方式书写 if 条件语句: + +- if-elif-else 块语句,其中 elif 和 else 块均可省略,并且 elif 块可以使用多次 + +```python +success = True +_result = "failed" +if success: + _result = "success" +``` + +```python +success = True +if success: + _result = "success" +else: + _result = "failed" +``` + +```python +_result = 0 +if condition == "one": + _result = 1 +elif condition == "two": + _result = 2 +elif condition == "three": + _result = 3 +else: + _result = 4 +``` + +- 条件表达式 ` if else `, 类似于 C 语言当中的 ` ? : ` 三元表达式 + +```python +success = True +_result = "success" if success else "failed" +``` + +注意:在书写 if-elif-else 块语句时注意书写 if 条件后的冒号 `:` 以及保持缩进的统一 + +除此之外,还可以在 list 或者 dict 结构中直接书写条件表达式(不同的是,在结构中书写的 if 表达式中需要书写的值而不是语句): + +- list + +```python +env = "prod" +data = [ + "env_value" + ":" + if env == "prod": + "prod" # 书写需要添加到 data 中的值,而不是语句 + else: + "other_prod" +] # ["env_value", ":", "prod"] +``` + +- dict + +```python +env = "prod" +config = { + if env == "prod": + MY_PROD_ENV = "prod_value" # 书写需要添加到 config 中的键-值对,而不是语句 + else: + OTHER_ENV = "other_value" +} # {"MY_PROD_ENV": "prod_value"} +``` + +## 10. 怎样表达 "与" "或" "非" 等逻辑运算? + +在 KCL 中,使用 `and` 表示"逻辑与", 使用 `or` 表示"逻辑或", 使用 `not` 表示"非", 与 C 语言当中的 `&&`, `||` 和 `~` 语义一致; + +```python +done = True +col == 0 +if done and (col == 0 or col == 3): + ok = 1 +``` + +对于整数的"按位与", "按位或"和"按位异或",在 KCL 中使用 `&`, `|` 和 `^` 运算符表示, 与 C 语言当中的 `&`, `|` 和 `^` 语义一致; + +```python +value = 0x22 +bitmask = 0x0f + +assert (value & bitmask) == 0x02 +assert (value & ~bitmask) == 0x20 +assert (value | bitmask) == 0x2f +assert (value ^ bitmask) == 0x2d +``` + +"逻辑或" `or` 的妙用:当需要书写诸如 `A if A else B` 类似的模式时,可以使用 `A or B` 进行简化,比如如下代码: + +```python +value = [0] +default = [1] +x0 = value if value else default +x1 = value or default # 使用 value or default 代替 value if value else default +``` + +## 11. 如何判断变量是否为 None/Undefined、字符串/dict/list 是否为空? + +请注意,在 if 表达式的条件判断中,`False`、`None`、`Undefined`、数字 `0`、空列表 `[]`、空字典 `{}` 和空字符串 `""`, `''`, `""""""`, `''''''` 都被视为值为 `假` 的表达式。 + +比如判断一个字符串变量 `strData` 既不为 `None/Undefined` 也不为空字符串时(字符串长度大于 0),就可以简单的使用如下表达式: + +```python +strData = "value" +if strData: + isEmptyStr = False +``` + +空字典和空列表判断举例: + +```python +_emptyList = [] +_emptyDict = {} +isEmptyList = False if _emptyList else True +isEmptyDict = False if _emptyDict else True +``` + +YAML 输出为: + +```yaml +isEmptyList: true +isEmptyDict: true +``` + +或者使用布尔函数 `bool` 进行判断 + +```python +_emptyList = [] +_emptyDict = {} +isEmptyList = bool(_emptyList) +isEmptyDict = bool(_emptyDict) +``` + +此外,如果我们想要判断一个变量仅为 `None`/`Undefined`,而不为空,则可以使用下面的表达式或者 `isnullish()` 内置函数 + +```python +a = None +_emptyList = [] +isEmptyList = bool(_emptyList) +isNullishList1 = _emptyList not in [None, Undefined] +isNullishList2 = isnullish(_emptyList) +``` + +## 12. 字符串怎样拼接、怎样格式化字符串、怎样检查字符串前缀、后缀?怎样替换字符串内容? + +- KCL 中可以使用 `+` 运算符连接两个字符串 + +```python +data1 = "string1" + "string2" # "string1string2" +data2 = "string1" + " " + "string2" # "string1 string2" +``` + +- KCL 中目前存在两种格式化字符串的方式: + - 字符串变量的 format 方法 `"{}".format()` + - 字符串插值 `${}` + +```python +hello = "hello" +a = "{} world".format(hello) +b = "${hello} world" +``` + +注意,如果想在 `"{}".format()` 中单独使用 `{` 字符或者 `}`, 则需要使用 `{{` 和 `}}` 分别对 `{` 和 `}` 进行转义,比如转义一个 JSON 字符串如下代码: + +```python +data = "value" +jsonData = '{{"key": "{}"}}'.format(data) +``` + +输出 YAML 为: + +```yaml +data: value +jsonData: '{"key": "value"}' +``` + +注意,如果不想 `${...}` 表示字符串插值 ,我们可以在 `$` 之前添加`\` 字符表示直接以字符串的形式输出 `${...}`。 + +```python +world = "world" +a = "hello {}".format(world) # "hello world" +b = "hello ${world}" # "hello world" +c1 = "$hello ${world}$" # "$hello world$" +c2 = "$" + "hello ${world}" + "$" # "$hello world$" +c3 = "$" + "hello \${world}" + "$" # "$hello ${world}$" +``` + +输出 YAML 为: + +```yaml +world: world +a: hello world +b: hello world +c: $hello world$ +c2: $hello world$ +``` + +- KCL 中使用字符串的 `startswith` 和 `endswith` 方法检查字符串的前缀和后缀 + +```python +data = "length" +isEndsWith = data.endswith("th") # True +isStartsWith = "length".startswith('len') # True +``` + +- KCL 中使用字符串的 replace 方法或者 regex.replace 函数替换字符串的内容 + +```python +import regex +data1 = "length".replace("len", "xxx") # 使用"xxx"替换"len", "xxxgth" +data2 = regex.replace("abc123", r"\D", "0") # 替换"abc123"中的所有非数字为"0", "000123" +``` + +其中,`r"\D"` 表示不需要使用 `\\` 转义 `\D` 中的反斜杠 `\`,多用于正则表达式字符串中 + +此外,我们可以在字符串格式化表达式中插入索引占位符或者关键字占位符用于格式化多个字符串 + +- 索引占位符 + +```python +x = '{2} {1} {0}'.format('directions', 'the', 'Read') +y = '{0} {0} {0}'.format('string') +``` + +输出为: + +```yaml +x: Read the directions +y: string string string +``` + +- 关键字占位符 + +```python +x = 'a: {a}, b: {b}, c: {c}'.format(a = 1, b = 'Two', c = 12.3) +``` + +输出为: + +```yaml +x: "a: 1, b: Two, c: 12.3" +``` + +## 13. 字符串中使用单引号和双引号的区别是什么? + +KCL 单引号和双引号字符串几乎没有区别。唯一的区别是,不需要在单引号字符串中使用 `\"` 转义双引号 `"`,不需要在双引号字符串中使用 `\'` 转义单引号引号 `'`。 + +```python +singleQuotedString = 'This is my book named "foo"' # don't need to escape double quotes in single quoted strings. +doubleQuotedString = "This is my book named 'foo'" # don't need to escape single quotes in double quoted strings. +``` + +此外在 KCL 中,使用三个单引号或者三个双引号组成的长字符串,无需在其中对单引号或者三引号进行转义 (除字符串首尾),比如如下例子: + +```python +longStrWithQuote0 = """Double quotes in long strings "(not at the beginning and end)""" +longStrWithQuote1 = '''Double quotes in long strings "(not at the beginning and end)''' +longStrWithQuote2 = """Single quotes in long strings '(not at the beginning and end)""" +longStrWithQuote3 = '''Single quotes in long strings '(not at the beginning and end)''' +``` + +输出 YAML: + +```yaml +longStrWithQuote0: Double quotes in long strings "(not at the beginning and end) +longStrWithQuote1: Double quotes in long strings "(not at the beginning and end) +longStrWithQuote2: Single quotes in long strings '(not at the beginning and end) +longStrWithQuote3: Single quotes in long strings '(not at the beginning and end) +``` + +## 14. 如何编写跨行的长字符串? + +KCL 中可以使用单引号字符串 + 换行符 `\n` 或者三引号字符串书写一个多行字符串,并且可以借助续行符 `\` 优化 KCL 字符串的形式,比如对于如下代码中的三个多行字符串变量,它们的制是相同的: + +```python +string1 = "The first line\nThe second line\nThe third line\n" +string2 = """The first line +The second line +The third line +""" +string3 = """\ +The first line +The second line +The third line +""" # 推荐使用 string3 长字符串的书写形式 +``` + +输出 YAML 为: + +```yaml +string1: | + The first line + The second line + The third line +string2: | + The first line + The second line + The third line +string3: | + The first line + The second line + The third line +``` + +## 15. 如何使用正则表达式? + +通过在 KCL 中导入正则表达式库 `import regex` 即可使用正则表达式,其中包含了如下函数: + +- **match**: 正则表达式匹配函数,根据正则表达式对输入字符串进行匹配,返回 bool 类型表示是否匹配成功 +- **split**: 正则表达式分割函数,根据正则表达式分割字符串,返回分割字串的列表 +- **replace**: 正则表达式替换函数,替换字符串中所有满足正则表达式的子串,返回被替换的字符串 +- **compile**: 正则表达式编译函数,返回 bool 类型表示是否是一个合法的正则表达式 +- **search**: 正则表达式搜索函数,搜索所有满足正则表达式的子串,返回子串的列表 + +使用举例: + +```python +import regex + +regex_source = "Apple,Google,Baidu,Xiaomi" +regex_split = regex.split(regex_source, ",") +regex_replace = regex.replace(regex_source, ",", "|") +regex_compile = regex.compile("$^") +regex_search = regex.search("aaaa", "a") +regex_find_all = regex.findall("aaaa", "a") +regex_result = regex.match("192.168.0.1", "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$") # 判断是否是一个IP字符串 +regex_result_false = regex.match("192.168.0,1", "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."+"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$") # 判断是否是一个IP字符串 +``` + +输出 YAML: + +```yaml +regex_source: Apple,Google,Baidu,Xiaomi +regex_split: + - Apple + - Google + - Baidu + - Xiaomi +regex_replace: Apple|Google|Baidu|Xiaomi +regex_compile: true +regex_search: true +regex_find_all: + - a + - a + - a + - a +regex_result: true +regex_result_false: false +``` + +对于比较长的正则表达式,还可以使用 r-string 忽略 `\` 符号的转义简化正则表达式字符串的书写: + +```python +import regex + +isIp = regex.match("192.168.0.1", r"^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])."+r"(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)."+r"(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)."+r"(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$") # 判断是否是一个IP字符串 +``` + +更多举例: + +```python +import regex + +schema Resource: + cpu: str = "1" + memory: str = "1024Mi" + disk: str = "10Gi" + check: + regex.match(cpu, r"^([+-]?[0-9.]+)([m]*[-+]?[0-9]*)$"), "cpu must match specific regular expression" + regex.match(memory, r"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"), "memory must match specific regular expression" + regex.match(disk, r"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"), "disk must match specific regular expression" +``` + +```python +import regex + +schema Env: + name: str + value?: str + check: + len(name) <= 63, "a valid env name must be no more than 63 characters" + regex.match(name, r"[A-Za-z_][A-Za-z0-9_]*"), "a valid env name must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_'" +``` + +## 16. KCL 当中的 schema 是什么含义? + +schema 是 KCL 中一种语言元素,用于定义配置数据的类型,像 C 语言中的 struct 或者 Java 中的 class 一样,在其中可以定义属性,每种属性具有相应的类型。 + +## 17. 如何声明 schema? + +KCL 中使用 schema 关键字可以定义一个结构,在其中可以申明 schema 的各个属性 + +```python +# 一个Person结构,其中具有属性字符串类型的firstName, 字符串类型的lastName, 整数类型的age +schema Person: + firstName: str + lastName: str + # age属性的默认值为0 + age: int = 0 +``` + +一个复杂例子: + +```python +schema Deployment: + name: str + cpu: int + memory: int + image: str + service: str + replica: int + command: [str] + labels: {str:str} +``` + +在上面的代码中,`cpu` 和 `memory` 被定义为整数 int 类型;`name`,`image` 和 `service` 是字符串 str 类型; `command` 是字符串类型的列表; labels 是字典类型,其键类型和值类型均为字符串。 + +## 18. 如何为 schema 属性添加 "不可变"、"必选" 约束? + +KCL 中使用 `?` 运算符定义一个 schema 的"可选"约束,schema 属性默认都是"必选"的 + +```python +# 一个Person结构,其中具有属性字符串类型的firstName, 字符串类型的lastName, 整数类型的age +schema Person: + firstName?: str # firstName是一个可选属性,可以赋值为None/Undefined + lastName?: str # age是一个可选属性,可以赋值为None/Undefined + # age属性的默认值为 18 + age: int = 18 # age是一个必选属性,不能赋值为None/Undefined,并且是一个不可变属性 + age = 10 # Error, age是一个不可变的属性 +``` + +## 19. 如何为 schema 中的属性编写校验规则? + +在 schema 定义当中可以使用 check 关键字编写 schema 属性的校验规则, 如下所示,check 代码块中的每一行都对应一个条件表达式,当满足条件时校验成功,当不满足条件时校验失败。条件表达式后可跟 `, "check error message"` 表示当校验失败时需要显示的信息 + +```python +import regex + +schema Sample: + foo: str # Required, 不能为None/Undefined, 且类型必须为str + bar: int # Required, 不能为None/Undefined, 且类型必须为int + fooList: [int] # Required, 不能为None/Undefined, 且类型必须为int列表 + color: "Red" | "Yellow" | "Blue" # Required, 字面值联合类型,且必须为"Red", "Yellow", "Blue"中的一个,枚举作用 + id?: int # Optional,可以留空,类型必须为int + + check: + bar >= 0 # bar必须大于等于0 + bar < 100 # bar必须小于100 + len(fooList) > 0 # fooList不能为None/Undefined,并且长度必须大于0 + len(fooList) < 100 # fooList不能为None/Undefined,并且长度必须小于100 + regex.match(foo, "^The.*Foo$") # regex 正则表达式匹配 + bar in range(100) # range, bar范围只能为1到99 + bar in [2, 4, 6, 8] # enum, bar只能取2, 4, 6, 8 + bar % 2 == 0 # bar必须为2的倍数 + all foo in fooList { + foo > 1 + } # fooList中的所有元素必须大于1 + any foo in fooList { + foo > 10 + } # fooList中至少有一个元素必须大于10 + abs(id) > 10 if id # check if 表达式,当 id 不为空时,id的绝对值必须大于10 +``` + +此外,上述 check 当中比较表达式还可以简写为: + +```python +0 <= bar < 100 +0 < len(fooList) < 100 +``` + +综上所述,KCL Schema 中支持的校验类型为: + +| 校验类型 | 使用方法 | +| -------- | ---------------------------------------------------------- | +| 范围校验 | 使用 `<`, `>` 等比较运算符 | +| 正则校验 | 使用 `regex` 系统库中的 `match` 等方法 | +| 长度校验 | 使用 `len` 内置函数,可以求 `list/dict/str` 类型的变量长度 | +| 枚举校验 | 使用字面值联合类型 | +| 非空校验 | 使用 schema 的可选/必选属性 | +| 条件校验 | 使用 check if 条件表达式 | + +## 20. 如何为 schema 及其属性添加文档注释? + +一个完整的 schema 属性注释使用三引号字符串表示,其中的结构如下所示: + +```python +schema Person: + """The schema person definition + + Attributes + ---------- + name : str + The name of the person + age : int + The age of the person + + See Also + -------- + Son: + Sub-schema Son of the schema Person. + + Examples + -------- + person = Person { + name = "Alice" + age = 18 + } + """ + name: str + age: int + +person = Person { + name = "Alice" + age = 18 +} +``` + +## 21. 如何基于 schema 编写配置?多个配置之间如何复用公共的配置? + +在 schema 实例化的过程中可以使用解包运算符 `**` 对公共的配置进行展开 + +```python +schema Boy: + name: str + age: int + hc: int + +schema Girl: + name: str + age: int + hc: int + +config = { + age = 18 + hc = 10 +} + +boy = Boy { + **config + name = "Bob" +} +girl = Girl { + **config + name = "Alice" +} +``` + +输出 YAML 为: + +```yaml +config: + age: 18 + hc: 10 +boy: + name: Bob + age: 18 + hc: 10 +girl: + name: Alice + age: 18 + hc: 10 +``` + +## 22. 基于 schema 编写配置时如何覆盖 schema 属性的默认值? + +在定义 schema 后,可以使用 schema 名称实例化相应的配置,使用 `:` 运算符对 schema 默认值进行 union, 使用 `=` 对 schema 默认值进行覆盖。对于 int/float/bool/str 类型的 schema 属性,union 和覆盖的效果相同; 对于 list/dict/schema 类型的 schema 属性,union 和覆盖的效果不同; + +```python +schema Meta: + labels: {str:str} = {"key1" = "value1"} + annotations: {str:str} = {"key1" = "value1"} + +meta = Meta { + labels: {"key2": "value2"} + annotations = {"key2" = "value2"} +} +``` + +输出 YAML 为: + +```yaml +meta: + labels: + key1: value1 + key2: value2 + annotations: + key2: value2 +``` + +## 23. 如何通过继承来复用 schema 定义? + +可以在 schema 定义处声明 schema 需要继承的 schema 名称: + +```python +# A person has a first name, a last name and an age. +schema Person: + firstName: str + lastName: str + # The default value of age is 0 + age: int = 0 + +# An employee **is** a person, and has some additional information. +schema Employee(Person): + bankCard: int + nationality: str + +employee = Employee { + firstName = "Bob" + lastName = "Green" + age = 18 + bankCard = 123456 + nationality = "China" +} +``` + +输出 YAML 为: + +```yaml +employee: + firstName: Bob + lastName: Green + age: 18 + bankCard: 123456 + nationality: China +``` + +注意: KCL 只允许 schema 单继承 + +## 24. 如何通过组合复用 schema 逻辑? + +可以使用 KCL schema mixin 复用 schema 逻辑,mixin 一般被用于 schema 内部属性的分离数据,和数据映射等功能,可以使 KCL 代码更具模块化和声明性。注意不同的 mixin 之间的混入属性不建议定义依赖关系,会使得 mixin 使用方式复杂,一般一个 mixin 中作不超过三个属性混入即可。 + +```python +schema Person: + mixin [FullNameMixin, UpperMixin] + + firstName: str + lastName: str + fullName: str + upper: str + +schema FullNameMixin: + fullName = "{} {}".format(firstName, lastName) + +schema UpperMixin: + upper = fullName.upper() + +person = Person { + firstName = "John" + lastName = "Doe" +} +``` + +输出 YAML 为: + +```yaml +person: + firstName: John + lastName: Doe + fullName: John Doe + upper: JOHN DOE +``` + +## 25. 如何导入其他 KCL 文件? + +通过 import 关键字可以导入其他 KCL 文件,KCL 配置文件被组织为模块。单个 KCL 文件被视为一个模块,目录被视为一个包,作为一个特殊的模块。import 关键字支持相对路径导入和绝对路径导入两种方式 + +比如对于如下目录结构: + +``` +. +└── root + ├── kcl.mod + ├── model + │ ├── model1.k + | ├── model2.k + │ └── main.k + ├── service + │ │── service1.k + │ └── service2.k + └── mixin + └── mixin1.k +``` + +对于 `main.k`, 相对路径导入和绝对路径导入分别可以表示为: + +```python +import service # 绝对路径导入, 根目录为kcl.mod所在的路径 +import mixin # 绝对路径导入, 根目录为kcl.mod所在的路径 + +import .model1 # 相对路径导入, 当前目录模块 +import ..service # 相对路径导入, 父目录 +import ...root # 相对路径导入, 父目录的父目录 +``` + +注意,对于 KCL 的入口文件 `main.k`, 其不能导入自身所在的文件夹,否则会发生循环导入错误: + +```python +import model # Error: recursively loading +``` + +## 26. 什么情况下可以省略 import ? + +除了 main 包当中的同一文件夹下的 KCL 可以相互引用而不需通过 import 相互引用,比如对于如下目录结构: + +``` +. +└── root + ├── kcl.mod + ├── model + │ ├── model1.k + | ├── model2.k + │ └── main.k + ├── service + │ │── service1.k + │ └── service2.k + └── mixin + └── mixin1.k +``` + +当 main.k 作为 KCL 命令行入口文件时, model 文件夹中的 main.k, model1.k 和 model2.k 中的变量不能相互引用,需要通过 import 导入,但是 service 文件夹中的 service1.k 和 service2.k 当中的变量可以互相引用,忽略 import + +service1.k + +```python +schema BaseService: + name: str + namespace: str +``` + +service2.k + +```python +schema Service(BaseService): + id: str +``` + +## 27. 有一行代码太长了,如何在语法正确的情况下优雅地换行? + +在 KCL 中可以使用续行符 `\` 进行换行, 并且在字符串中也可以使用 `\` 表示续行 + +长字符串连接续行举例: + +```python +longString = "Too long expression " + \ + "Too long expression " + \ + "Too long expression " +``` + +推导表达式续行举例: + +```python +data = [1, 2, 3, 4] +dataNew = [ + d + 2 \ + for d in data \ + if d % 2 == 0 +] +``` + +if 表达式续行举例: + +```python +condition = 1 +data1 = 1 \ + if condition \ + else 2 +data2 = 2 \ +if condition \ +else 1 +``` + +三引号字符串内部续行举例: + +```python +longString = """\ +The first line\ +The continue second line\ +""" +``` + +注意: 使用续行符 `\` 的同时缩进的保持, 如下所示: + +错误用例: + +```python +data1 = [ + 1, 2, + 3, 4 \ +] # Error, 需要保持右方括号]的缩进 + +data2 = [ + 1, 2, + 3, 4 +] # Error, 需要数字1和3的缩进统一 +``` + +正确用例: + +```python +data1 = [ + 1, 2, + 3, 4 +] # Right, 带缩进的列表定义 + +data2 = [ \ + 1, 2, \ + 3, 4 \ +] # Right, 使用续行符的列表定义, 实际效果是单行列表 + +data3 = [ \ + 1, 2, \ + 3, 4 \ +] # Right, 使用续行符的列表定义, 无需保持缩进, 实际效果是单行列表 +``` + +## 28. \*_, _ 这些符号是什么意思? + +- `**`, `*` 出现在 dict/list 外部时分别表示乘方运算符和乘法运算符 + +```python +data1 = 2 ** 4 # 2的4次方等于16 +data2 = 2 * 3 # 2乘以3等于6 +``` + +- `**`, `*` 出现在 dict/list 内部时表示解包运算符,经常用于 list/dict 的解包和合并, 与 Python 当中的解包运算符用法相同 + +dict 的解包: + +```python +data = {"key1" = "value1"} +dataUnpack = {**data, "key2" = "value2"} # 将data解包合并入dataUnpack中, {"key1": "value1", "key2": "value2"} +``` + +list 的解包: + +```python +data = [1, 2, 3] +dataUnpack = [*data, 4, 5, 6] # 将data解包合并入dataUnpack中, [1, 2, 3, 4, 5, 6] +``` + +## 29. 如何取 list/dict/schema 的子元素 + +在 KCL 中可以使用 select 表达式或者 subscript 表达式取 list/dict/schema 的子元素 + +- 对于 list 类型,可以使用 `[]` 取列表中的某一个元素或者某一些元素 + +```python +data = [1, 2, 3] # 定义一个整数类型的数组 +theFirstItem = data[0] # 取数组中索引为0的元素,即第一个元素 1 +theSecondItem = data[1] # 取数组中索引为1的元素,即第一个元素 2 +``` + +注意:索引的取值不能超出列表的长度,否则会发生错误,可以使用 `len` 函数获得数组的长度 + +```python +data = [1, 2, 3] +dataLength = len(data) # 数组长度为3 +item = data[3] # 发生数组索引越界错误 +``` + +此外,还可以使用负数索引倒序获得列表中的元素 + +```python +data = [1, 2, 3] +item1 = data[-1] # 取数组中索引为-1的元素,即最后一个元素 3 +item2 = data[-2] # 取数组中索引为-2的元素,即倒数第二个元素 2 +``` + +综上,列表索引的取值范围为 `[-len, len - 1]` + +当想要取得列表的一部分时,可以在 `[]` 中使用切片表达式,其具体语法为 `[<列表开始索引>:<列表终止索引>:<列表遍历步长>]`,注意索引开始终止的取值区间为 `左闭右开[<列表开始索引>, <列表终止索引>)`,注意三个参数均可省略不写 + +```python +data = [1, 2, 3, 4, 5] +dataSlice0 = data[1:2] # 取列表中索引开始为 1, 终止索引为 2 的元素集合 [2] +dataSlice1 = data[1:3] # 取列表中索引开始为 1, 终止索引为 3 的元素集合 [2, 3] +dataSlice2 = data[1:] # 取列表中索引开始为 1, 终止索引为 最后一个索引 的元素集合 [2, 3, 4, 5] +dataSlice3 = data[:3] # 取列表中索引开始为 第一个索引, 终止索引为 3 的元素集合 [1, 2, 3] +dataSlice4 = data[::2] # 取列表中索引开始为 第一个索引, 终止索引为 最后一个索引 的元素集合(步长为2) [1, 3, 5] +dataSlice5 = data[::-1] # 反转一个列表,[5, 4, 3, 2, 1] +dataSlice6 = data[2:1] # 当开始,终止,步长三个参数组合不满足条件时返回空列表 [] + +``` + +- 对于 dict/schema 类型,可以使用 `[]` 和 `.` 两种方式取 dict/schema 中的子元素 + +```python +data = {key1: "value1", key2: "value2"} +data1 = data["key1"] # "value1" +data2 = data.key1 # "value1" +data3 = data["key2"] # "value2" +data4 = data.key2 # "value2" +``` + +```python +schema Person: + name: str = "Alice" + age: int = 18 + +person = Person {} +name1 = person.name # "Alice" +name2 = person["name"] # "Alice" +age1 = person.age # 18 +age2 = person.age # 18 +``` + +当键值在 dict 中不存在时,返回未定义值 `Undefined` + +```python +data = {key1 = "value1", key2 = "value2"} +data1 = data["not_exist_key"] # Undefined +data2 = data.not_exist_key # Undefined +``` + +可以使用 `in` 关键字判断某个键值是否在 dict/schema 中存在 + +```python +data = {key1 = "value1", key2 = "value2"} +exist1 = "key1" in data # True +exist2 = "not_exist_key" in data # False +``` + +当键值中存在 `.` 时或者需要运行时取一个键值变量对应的值时,只能使用 `[]` 方式,如无特殊情况,使用 `.` 即可: + +```python +name = "key1" +data = {key1 = "value1", key2 = "value2", "contains.dot" = "value3"} +data1 = data[name] # "value1" +data2 = data["contains.dot"] # "value3" +# 注意这样子是不对的 data3 = data.contains.dot +``` + +注意:上述取子元素的运算符不能对非 list/dict/schema 集合类型的值进行操作,比如整数,空值等。 + +```python +data = 1 +data1 = 1[0] # error +``` + +```python +data = None +data1 = None[0] # error +``` + +在取集合类型的子元素时往往要进行非空或者长度判断: + +```python +data = [] +item = data[0] if data else None +``` + +可以使用非空判断符 `?` 添加在 `[]`, `.` 的前面表示进行 if 非空判断,当不满足条件时返回 None,比如上述代码可以简化为: + +```python +data = [] +item1 = data?[0] # 当data为空时,返回空值 None +item2 = data?[0] or 1 # 当data为空时,返回空值 None, 如果不想返回 None, 还可与 or 运算符连用返回其他默认值 +``` + +使用 `?` 可以进行递归调用, 避免复杂繁琐的非空判断 + +```python +data = {key1.key2.key3 = []} +item = data?.key1?.key2?.key3?[0] +``` + +## 30. 如何在 KCL 代码中判断变量的类型 + +KCL typeof built-in 函数可以在该函数执行时立即返回一个变量的类型(字符串表示)用于类型断言 + +用法举例: + +```python +import sub as pkg + +_a = 1 + +t1 = typeof(_a) +t2 = typeof("abc") + +schema Person: + name?: any + +_x1 = Person{} +t3 = typeof(_x1) + +_x2 = pkg.Person{} +t4 = typeof(_x2) +t5 = typeof(_x2, full_name=True) + +t6 = typeof(_x1, full_name=True) + +# 输出 +# t1: int +# t2: str +# t3: Person +# t4: Person +# t5: sub.Person +# t6: __main__.Person +``` + +## 31. 关键字和 KCL 变量名冲突了可以怎么解决? + +对于与关键字冲突的标识符,可以在标识符前添加 `$` 前缀用于定义一个关键字标识符,比如如下代码中使用了 `if`, `else` 等关键字作为标识符并且可以得到相应的 YAML 输出 + +```python +$if = 1 +$else = "s" + +schema Data: + $filter: str = "filter" + +data = Data {} +``` + +输出 YAML: + +```yaml +data: + filter: filter +if: 1 +else: s +``` + +注意:在非关键字标识符前添加 `$` 前缀的效果与不添加相同 + +```python +_a = 1 +$_a = 2 # 等效于 `_a = 2` +``` + +## 32. KCL 的内置类型是 KCL 的关键字吗?是否可用于变量的定义 + +KCL 的内置类型包括 `int`, `float`, `bool` 和 `str` 四种类型,它们不是 KCL 的关键字,可用于变量的定义,比如如下代码: + +```py +int = 1 +str = 2 +``` + +输出 YAML 为: + +```yaml +int: 1 +str: 2 +``` + +注意:如无特殊需求,不建议变量的名称取这些内置类型,因为在有些语言当中,它们作为关键字存在 + +## 33. 如何在 KCL 中实现类似 Enum 枚举的功能 + +有两种方式可以在 KCL 中实现 Enum 枚举的方式 + +- (推荐)使用**字面值类型**的**联合类型** + +```python +schema Person: + name: str + gender: "Male" | "Female" + +person = Person { + name = "Alice" + gender = "Male" # gender 只能为 "Male" 或者 "Female" +} +``` + +一个复杂例子 + +```python +schema Config: + colors: ["Red" | "Yellow" | "Blue"] # colors 是一个枚举数组 + +config = Config { + colors = [ + "Red" + "Blue" + ] +} +``` + +- 使用 schema 的 check 表达式 + +```python +schema Person: + name: str + gender: "Male" | "Female" + + check: + gender in ["Male", "Female"] + +person = Person { + name = "Alice" + gender = "Male" # gender 只能为 "Male" 或者 "Female" +} +``` + +## 34. 如何求字典 dict 的长度 + +在 KCL 中可以使用 `len` 内置函数直接求 dict 的长度 + +```python +len1 = len({k1: "v1"}) # 1 +len2 = len({k1: "v1", k2: "v2"}) # 2 +varDict = {k1 = 1, k2 = 2, k3 = 3} +len3 = len(varDict) # 3 +``` + +此外,使用 `len` 函数还可以求 `str` 和 `list` 类型长度 + +```python +len1 = len("hello") # 5 +len2 = len([1, 2, 3]) # 3 +``` + +## 35. 如何在 KCL 中编写带条件的配置 + +在 KCL 中,除了支持在顶级的语句中书写 `if-elif-else` 条件表达式以外,还支持在 KCL 复杂结构(list/dict/schema)中书写条件表达式,支持带条件的配置书写。 + +```python +x = 1 +# List 结构中的 if 条件语句 +dataList = [ + if x == 1: 1 +] +# Dict 结构中的 if 条件语句 +dataDict = { + if x == 1: key1 = "value1" # 可以同一行书写 + elif x == 2: + key2 = "value2" # 可以跨行书写 +} +# Schema 结构中的 if 条件语句 +schema Config: + id?: int +env = "prod" +dataSchema = Config { + if env == "prod": + id = 1 + elif env == "pre": + id = 2 + elif env == "test": + id = 3 +} +``` + +## 36. KCL 中的 == 运算符会作深度比较嘛? + +KCL 中的 `==` 运算符 + +- 对于基本类型 `int`, `float`, `bool`, `str` 的变量是直接比较它们的值是否相等 +- 对于复合类型 `list`, `dict`, `schema` 的变量会深度递归地比较其中的子元素是否相等 + - `list` 类型深度递归递归比较每个索引的值以及长度 + - `dict`/`schema` 类型深度递归比较每个属性的值(与属性出现的顺序无关) + +```python +print([1, 2] == [1, 2]) # True +print([[0, 1], 1] == [[0, 1], 1]) # True +print({k1 = 1, k2 = 2} == {k2 = 2, k1 = 1}) # True + +print([1, 2] == [1, 2, 3]) # False +print({k1 = 1, k2 = 2, k3 = 3} == {k2 = 2, k1 = 1}) # False +``` + +## 37. 如何对 KCL 中已有的配置块进行修改 + +在 KCL 中,存在三种**属性运算符** `=`、`+=`、`:`,可以用来对已有配置块进行修改,并且可以使用**解包运算符** `**` 等"继承"一个配置块的所有属性字段和值。 + +- `=` 属性运算符表示覆盖,使用 `=` 运算符可以对属性进行有优先级的覆盖/删除,(如果是用 `Undefined` 覆盖则表示删除) +- `+=` 属性运算符表示添加,一般用于对 list 类型的属性添加子元素,`+=` 属性运算符后跟的操作数类型也只能为 list 类型 +- `:` 属性运算符表示幂等合并,当值发生冲突时进行报错,不冲突时进行合并 + +### 覆盖属性运算符= + +最常使用的属性运算符是 `=`,表示一个属性的赋值,多次对同一个属性进行使用时表示覆盖,对于 `{}` 外的全局变量或者 `{}` 内的属性均表示使用值覆盖这个全局变量或者属性 + +```python +data = { # 定义一个字典类型的变量 data + a = 1 # 使用 = 在 data 中声明一个值为 1 的属性 a + b = 2 # 使用 = 在 data 中声明一个值为 2 的属性 b +} # 最终 data 的值为 {"a": 1, "b": 2} +``` + +在 schema 实例化处也可以使用覆盖属性运算符实现对 schema 默认值的覆盖效果,一般在创建新的 schema 实例时如无特殊的需求,一般使用 `=` 即可 + +```python +schema Person: + name: str = "Alice" # schema Person 的 name 属性具有默认值 "Alice" + age: int = 18 # schema Person 的 age 属性具有默认值 18 + +bob = Person { + name = "Bob" # "Bob" -> "Alice", 属性 name 的值 "Bob" 的值会覆盖 schema Person name 属性的默认值 "Alice" + age = 10 # 10 -> 18, 属性 age 的值 10 的值会覆盖 schema Person age 属性的默认值 18 +} # 最终 bob 的值为 {"name": "Bob", age: 10} +``` + +### 插入属性运算符 += + +插入属性运算符表示对一个属性的值进行原地添加,比如向一个 list 类型的属性添加新的元素 + +```python +data = { + args = ["kcl"] # 使用 = 在 data 中声明一个值为 ["kcl"] 的属性 args + args += ["-Y", "settings.yaml"] # 使用 += 运算符向属性 args 中添加两个元素"-Y", "settings.yaml" +} # 最终 data 的值为 {"args": ["kcl", "-Y", "settings.yaml"]} +``` + +### 合并属性运算符: + +合并属性运算符表示对一个属性的不同配置块值进行幂等的合并,当需要合并的值发生冲突时进行报错,多用于复杂配置合并场景 + +```python +data = { + labels: {key1: "value1"} # 定义一个 labels, 它的类型为 dict, 值为 {"key1": "value1"} + labels: {key2: "value2"} # 使用 : 将 labels 不同的配置值进行合并 +} # 最终 data 的值为 {"labels": {"key1": "value1", "key2": "value2"}} +``` + +合并属性运算符属于幂等运算符,需要合并的配置块的书写顺序不影响其最终结果,比如上述例子中的两个 `labels` 属性也可以调换顺序书写 + +```python +data = { # 同一个属性 labels 的合并书写顺序不影响最终结果 + labels: {key2: "value2"} # 定义一个 labels, 它的类型为 dict, 值为 {"key2": "value2"} + labels: {key1: "value1"} # 使用 : 将 labels 不同的配置值进行合并 +} # 最终 data 的值为 {"labels": {"key1": "value1", "key2": "value2"}} +``` + +注意:合并属性运算符会对合并的值进行冲突检查,当需要合并的配置值发生冲突时进行报错 + +```python +data = { + a: 1 # a 的值为 1 + a: 2 # Error: a 的值 2 不能与 a 的值 1 进行合并,因为其结果存在冲突,且合并是不可交换的 +} +``` + +```python +data = { + labels: {key: "value"} + labels: {key: "override_value"} # Error: 两个 labels 的 key 属性的值 "value" 和 "override_value" 是冲突的,不可合并 +} +``` + +合并运算符对不同类型的使用方式不同 + +- 不同类型的属性不能进行合并 +- 当属性为 int/float/str/bool 等基本类型时,运算符会判断需要合并的值是否相等,不相等时发生合并冲突错误 + +```python +data = { + a: 1 + a: 1 # Ok + a: 2 # Error +} +``` + +- 当属性为 list 类型时 + - 当需要合并的两个 list 长度不相等时,发生合并冲突错误 + - 当需要合并的两个 list 长度相等时,按照索引递归地合并 list 当中的每一个元素 + +```python +data = { + args: ["kcl"] + args: ["-Y", "settings.yaml"] # Error: 两个 args 属性的长度不相同,不能进行合并 + env: [{key1: "value1"}] + env: [{key2: "value2"}] # Ok: 最终 env 属性的值为 [{"key1": "value1"}, {"key2": "value2"}] +} +``` + +- 当属性为 dict/schema 类型时,按照 key 递归地合并 dict/schema 当中的每一个元素 + +```python +data = { + labels: {key1: "value1"} + labels: {key2: "value2"} + labels: {key3: "value3"} +} # 最终 data 的值为 {"labels": {"key1": "value1", "key2": "value2", "key3": "value3"}} +``` + +- 任意类型的属性与 None/Undefined 合并的结果都是其自身 + +```python +data = { + args: ["kcl"] + args: None # Ok + args: Undefined #Ok +} # 最终 data 的值为 {"args": ["kcl"]} +``` + +支持顶级变量使用 `:` 属性声明与合并(仍然可使用 `config = Config {}` 的方式声明一个配置块) + +```python +schema Config: + id: int + value: str + +config: Config { + id: 1 +} +config: Config { + value: "1" +} +""" +此处定义了两个 Config 配置块,使用 : 运算符将可以两个配置块合并在一起,其合并的等效代码如下: +config: Config { + id: 1 + value: "1" +} +""" +``` + +综上所述,合并属性运算符 `:` 的使用场景主要为复杂数据结构 list/dict/schema 的合并操作,一般情况如无特殊需求使用 `=` 和 `+=` 两种属性运算符即可,因此属性运算符的最佳实践如下 + +- 对于基本类型,采用 `=` 运算符 +- 对于 list 类型,一般采用 `=` 和 `+=` 运算符,使用 `=` 表示完全覆盖 list 属性,使用 `+=` 表示向 list 中添加元素 +- 对于 dict/schema 类型,一般采用 `:` 运算符 + +此外,当已经存在一个配置时,可以使用解包运算符 `**` 获得此配置的所有字段值并对其中的字段使用不同属性运算符进行修改,并获得一个新的配置 + +```python +configBase = { + intKey = 1 # 一个 int 类型的属性 + floatKey = 1.0 # 一个 float 类型的属性 + listKey = [0] # 一个 list 类型的属性 + dictKey = {key1: "value1"} # 一个 dict 类型的属性 +} +configNew = { + **configBase # 将 configBase 解包内联到 configNew 中 + intKey = 0 # 使用 覆盖属性运算符 = 将 intKey 属性覆盖为 1 + floatKey = Undefined # 使用 覆盖属性运算符 = 删除 floatKey 属性 + listKey += [1] # 使用 添加属性运算符 += 为 listKey 属性尾部添加一个属性 1 + dictKey: {key2: "value2"} # 使用 合并属性运算符 : 为 dictKey 属性扩展一个键-值对 +} +``` + +输出的 YAML 结果为: + +```yaml +configBase: + intKey: 1 + floatKey: 1.0 + listKey: + - 0 + dictKey: + key1: value1 +configNew: + intKey: 0 + listKey: + - 0 + - 1 + dictKey: + key1: value1 + key2: value2 +``` + +或者可以使用 `|` 运算符对两个配置块合并: + +```python +configBase = { + intKey = 1 # 一个 int 类型的属性 + floatKey = 1.0 # 一个 float 类型的属性 + listKey = [0] # 一个 list 类型的属性 + dictKey = {key1: "value1"} # 一个 dict 类型的属性 +} +configNew = configBase | { # 使用 | 进行合并 + intKey = 0 # 使用 覆盖属性运算符 = 将 intKey 属性覆盖为 1 + floatKey = Undefined # 使用 覆盖属性运算符 = 删除 floatKey 属性 + listKey += [1] # 使用 添加属性运算符 += 为 listKey 属性尾部添加一个属性 1 + dictKey: {key2: "value2"} # 使用 合并属性运算符 : 为 dictKey 属性扩展一个键-值对 +} +``` + +输出的 YAML 结果为: + +```yaml +configBase: + intKey: 1 + floatKey: 1.0 + listKey: + - 0 + dictKey: + key1: value1 +configNew: + intKey: 0 + listKey: + - 0 + - 1 + dictKey: + key1: value1 + key2: value2 +``` + +### KCL 发生 conflicting values on the attribute 'attr' between {value1} and {value2} 错误的解决方式 + +当 KCL 发生类似 conflicting values on the attribute 'attr' between {value1} and {value2} 错误时,一般是合并属性运算符 `:` 的使用问题,表明 `value1` 和 `value2` 配置进行合并时在属性 `attr` 处发生了冲突错误。一般情况将 value2 的 attr 属性修改为其他属性运算符即可,使用 `=` 表示覆盖,使用 `+=` 表示添加 + +比如对于如下代码: + +```python +data = {k: 1} | {k: 2} # Error: conflicting values on the attribute 'k' between {'k': 1} and {'k': 2} +``` + +则可以使用 `=` 属性运算符修改为如下形式 + +```python +data = {k: 1} | {k = 2} # Ok: the value 2 will override the value 1 through the `=` operator +``` + +### 使用 `json_merge_patch` 库合并配置 + +如果我们对外部读取的配置有合并诉求,比如下面的代码显示的那样,则可以使用 `json_merge_patch` 库来操作,因为外部配置默认的属性运算符为 `:`, 可能会遇到合并冲突错误 + +```python +_vals1 = yaml.decode(file.read("...")) +_vals2 = option("...") + +_vals = _vals1 | _vals2 +``` + +`json_merge_patch` 库使用的方式详见[这里](https://github.com/kcl-lang/modules/tree/main/json_merge_patch) + +## 38. KCL 中如何同时遍历多个元素 + +KCL 中可以使用 for 推导表达式遍历多个元素 + +- 举例 1: 使用 for 进行 2 维元素遍历 + +```python +dimension1 = [1, 2, 3] # dimension1 列表的长度是 3 +dimension2 = [1, 2, 3] # dimension2 列表的长度是 3 +matrix = [x + y for x in dimension1 for y in dimension2] # matrix 列表的长度是 9 = 3 * 3 +``` + +输出结果如下: + +```yaml +dimension1: + - 1 + - 2 + - 3 +dimension2: + - 1 + - 2 + - 3 +matrix: + - 2 + - 3 + - 4 + - 3 + - 4 + - 5 + - 4 + - 5 + - 6 +``` + +- 举例 2: 使用 for 循环配合 zip 内置函数按照索引一一对应对多个列表进行遍历 + +```python +dimension1 = [1, 2, 3] # dimension1 列表的长度是 3 +dimension2 = [1, 2, 3] # dimension2 列表的长度是 3 +dimension3 = [d[0] + d[1] for d in zip(dimension1, dimension2)] # dimension3 列表的长度是 3 +``` + +输出结果如下: + +```yaml +dimension1: + - 1 + - 2 + - 3 +dimension2: + - 1 + - 2 + - 3 +dimension3: + - 2 + - 4 + - 6 +``` + +## 39. KCL 中如何为 option 函数设定默认值 + +在 KCL 中,当 option 属性的值为 None/Undefined 空时,可以使用逻辑或 `or` 直接指定一个默认值 + +```python +value = option("key") or "default_value" # 当 key 的值存在时,取 option("key") 的值,否则取 "default_value" +``` + +或者使用 option 函数的 default 参数 + +```python +value = option("key", default="default_value") # 当 key 的值存在时,取 option("key") 的值,否则取 "default_value" +``` + +## 40. KCL 中 schema 怎么检查多个属性不能同时为空或同时设置 + +在 KCL 中,对于 schema 的单个属性不能为空可以使用属性非空标记 + +```python +schema Person: + name: str # required. name 不能为空 + age: int # required. age 不能为空 + id?: int # optional. id 可以留空 +``` + +而对于需要检查 schema 属性不能同时为空或者只能有一者为空的情况时,需要借助 schema check 表达式进行书写,下面以同一个 schema Config 的两个属性 a, b 为例进行说明 + +- Config 的 a, b 属性不能同时为空 + +```python +schema Config: + a?: str + b?: str + + check: + a or b, "a属性和b属性不能同时为空" +``` + +- Config 的 a, b 属性只能有一个为空或者都为空(不能同时存在或不为空) + +```python +schema Config: + a?: str + b?: str + + check: + not a or not b, "a属性和b属性不能同时填写" +``` + +## 41. KCL 中 import 了某个文件但是找不到其同目录下其他 KCL 文件定义的 schema 可能是什么原因 + +可能是与使用 import 仅导入了这个文件夹的这一个文件导致,在 KCL 中,import 支持导入整个文件夹,也支持导入某一个文件夹下的的某一个 KCL 文件,比如对于如下目录结构 + +``` +. +├── kcl.mod +├── main.k +└── pkg + ├── pkg1.k + ├── pkg2.k + └── pkg3.k +``` + +在根目录下存在入口文件 main.k,可以在 main.k 中书写如下代码导入整个 pkg 文件夹,此时 pkg 文件夹下的所有 schema 定义互相可见 + +```python +import pkg +``` + +还可以书写如下代码导入单个文件 pkg/pkg1.k,此时 pkg1.k 不能找到其他文件即 pkg2.k/pkg3.k 下的 schema 定义 + +```python +import pkg.pkg1 +``` + +## 42. KCL 中的缩进是如何处理的? + +在 KCL 中,在出现冒号 `:`、中括号对 `[]` 以及大括号对 `{}` 时,一般需要使用换行 + 缩进,同一缩进级的缩进空格数需要保持一致,一个缩进级一般采用 4 个空格表示 + +- 冒号 `:` 后跟换行 + 缩进 + +```python +"""if 语句中的缩进""" +_a = 1 +_b = 1 +if _a >= 1: # 冒号后跟换行+缩进 + if _a > 8: + _b = 2 + elif a > 6: + _b = 3 + +"""schema 定义中的缩进""" +schema Person: # 冒号后跟换行+缩进 + name: str + age: int +``` + +- 中括号对 `[]` 后跟换行 + 缩进 + +```python +data = [ # 左中括号 [ 后跟换行+缩进 + 1 + 2 + 3 +] # 右中括号 ] 前取消缩进 +``` + +```python +data = [ # 左中括号 [ 后跟换行+缩进 + i * 2 for i in range(5) +] # 右中括号 ] 前取消缩进 +``` + +- 大括号对 `{}` 后跟换行 + 缩进 + +```python +data = { # 左大括号 { 后跟换行+缩进 + k1 = "v1" + k2 = "v2" +} # 右大括号 } 前取消缩进 +``` + +```python +data = { # 左大括号 { 后跟换行+缩进 + str(i): i * 2 for i in range(5) +} # 右大括号 } 前取消缩进 +``` + +## 43. 如何为 KCL 代码编写简单的测试? + +KCL 目前的版本还不支持内部程序调试,可以使用 assert 语句以及 print 函数实现数据的断言和打印查看 + +```python +a = 1 +print("The value of a is", a) +assert a == 1 +``` + +此外,还可以借助 kcl test 测试工具编写 KCL 内部编写测试用例 + +假设有 hello.k 文件,代码如下: + +```python +schema Person: + name: str = "kcl" + age: int = 1 + +hello = Person { + name = "hello kcl" + age = 102 +} +``` + +构造 hello_test.k 测试文件,内容如下: + +```python +test_person = lambda { + a = Person{} + assert a.name == 'kcl' +} + +test_person_age = lambda { + a = Person{} + assert a.age == 1 +} + +test_person_name_and_age = lambda { + a = Person{} + assert a.name == "kcl" + assert a.age == 1 +} +``` + +然后在目录下执行 kcl test 命令: + +``` +kcl test +``` + +## 44. KCL 中如何定义函数或定义方法? + +schema 结构在一定程度上充当了函数的功能,并且这个函数具有多个输入参数和多个输出参数的能力,比如如下代码可以实现一个斐波那契数列的功能: + +```python +schema Fib: + n: int + value: int = 1 if n <= 2 else (Fib {n: n - 1}).value + (Fib {n: n - 2}).value + +fib8 = (Fib {n: 8}).value +``` + +输出结果为: + +```yaml +fib8: 21 +``` + +一个合并列表为字典的 schema 函数 + +```python +schema UnionAll[data, n]: + _?: [] = data + value?: {:} = ((UnionAll(data=data, n=n - 1) {}).value | data[n] if n > 0 else data[0]) if data else {} + +schema MergeList[data]: + """Union一个列表中的所有元素返回合并字典 + + [{"key1": "value1"}, {"key2": "value2"}, {"key3": "value3"}] -> {"key1": "value1", "key2": "value2", "key3": "value3"} + """ + _?: [] = data + value?: {:} = (UnionAll(data=data, n=len(data) - 1) {}).value if data else {} +``` + +此外,KCL 支持使用 `lambda` 关键字定义一个函数: + +```python +func = lambda x: int, y: int -> int { + x + y +} +a = func(1, 1) # 2 +``` + +lambda 函数具有如下特性: + +- lambda 函数将最后一个表达式的值作为函数的返回值,空函数体返回 None。 +- 返回值类型注解可以省略,返回值类型为最后一个表达式值的类型 +- 函数体中没有与顺序无关的特性,所有的表达式都是按顺序执行的 + +```python +_func = lambda x: int, y: int -> int { + x + y +} # 使用 lambda 表达式定义一个函数 +_func = lambda x: int, y: int -> int { + x - y +} # Ok +_func = lambda x: int, y: int -> str { + str(x + y) +} # Error (int, int) -> str can't be assigned to (int, int) -> int +``` + +lambda 函数对象不能参与任何计算,只能在赋值语句和调用语句中使用。 + +```python +func = lambda x: int, y: int -> int { + x + y +} +x = func + 1 # Error: unsupported operand type(s) for +: 'function' and 'int(1)' +``` + +```python +a = 1 +func = lambda x: int { + x + a +} +funcOther = lambda f, para: int { + f(para) +} +r = funcOther(func, 1) # 2 +``` + +输出为: + +```python +a: 1 +r: 2 +``` + +可以定义一个匿名函数并直接调用 + +```python +result = (lambda x, y { + z = 2 * x + z + y +})(1, 1) # 3 +``` + +可以在 for 循环使用使用匿名函数 + +```python +result = [(lambda x, y { + x + y +})(x, y) for x in [1, 2] for y in [1, 2]] # [2, 3, 3, 4] +``` + +可以在 KCL schema 中定义并使用函数 + +```python +_funcOutOfSchema = lambda x: int, y: int { + x + y +} +schema Data: + _funcInSchema = lambda x: int, y: int { + x + y + } + id0: int = _funcOutOfSchema(1, 1) + id1: int = _funcInSchema(1, 1) + id2: int = (lambda x: int, y: int { + x + y + })(1, 1) +``` + +输出 YAML 为: + +```yaml +data: + id0: 2 + id1: 2 + id2: 2 +``` + +## 45. 为什么变量赋值为枚举类型(字面值联合类型)时会报错 + +在 KCL 中,被定义为字面值联合类型的属性,在赋值时仅允许接收一个字面值或者同为字面值联合类型的变量,比如如下代码是正确的: + +```python +schema Data: + color: "Red" | "Yellow" | "Blue" + +data = Data { + color = "Red" # Ok, 赋值为 "Red"、"Yellow" 和 "Blue" 均可 +} +``` + +然而以下代码是错误的: + +```python +schema Data: + color: "Red" | "Yellow" | "Blue" + +_color = "Red" + +data = Data { + color = _color # Error: expect str(Red)|str(Yellow)|str(Blue), got str +} +``` + +这是因为没有为变量 `_color` 申明一个类型,它会被 KCL 编译器推导为 `str` 字符串类型,因此当一个 “较大” 的类型 `str` 赋值为一个 “较小” 的类型时 `"Red" | "Yellow" | "Blue"` 会报错,一个解决方式是为 `_color` 变量声明一个类型,以下代码是正确的: + +```python +schema Data: + color: "Red" | "Yellow" | "Blue" + +_color: "Red" | "Yellow" | "Blue" = "Red" + +data = Data { + color = _color # Ok +} +``` + +进一步地,我们可以使用类型别名来简化枚举(字面值联合类型的书写),比如如下代码: + +```python +type Color = "Red" | "Yellow" | "Blue" # 定义一个类型别名,可以在不同的地方重复使用,降低代码书写量 + +schema Data: + color: Color + +_color: Color = "Red" + +data = Data { + color = _color # Ok +} +``` + +## 46. 过程式的 for 循环 + +KCL 中为何不支持过程式的 for 循环! + +KCL 提供了推导表达式以及 all/any/map/filter 表达式等用于对一个集合元素进行处理,满足大部分需求,提供过程式的 for 循环体从目前场景看需求暂时不强烈,因此暂未提供过程式的 for 循环支持 + +此外,KCL 中虽然没有支持过程式的 for 循环,但是可以通过 for 循环和 lambda 函数“构造”相应的过程式 for 循环 + +```python +result = [(lambda x: int, y: int -> int { + # 在其中书写过程式的 for 循环逻辑 + z = x + y + x * 2 +})(x, y) for x in [1, 2] for y in [1, 2]] # [2, 2, 4, 4] +``` + +## 47. 默认变量不可变 + +KCL 变量不可变性是指 KCL 顶层结构中的非下划线 `_` 开头的导出变量初始化后不能被改变。 + +```python +schema Person: + name: str + age: int + +a = 1 # a会输出到YAML中,一旦赋值不可修改 +_b = 1 # _b变量以下划线开头命名,不会输出到YAML中, 可多次赋值修改 +_b = 2 +alice = Person { + name = "Alice" + age = 18 +} +``` + +规定变量不可变的方式分为两类: + +- schema 外的非下划线顶层变量 + +```python +a = 1 # 不可变导出变量 +_b = 2 # 可变非导出变量 +``` + +## 48. 在 KCL 中存在类似 Go `interface{}`/`any` 或者 Java `Object` 的类型嘛? + +在 KCL 中,我们可以使用 `any` 类型注解来定义一个变量存储任意类型比如整数、字符串、schema 结构等数据。比如如下例子: + +```python +schema Data: + id: int = 1 + +var_list: [any] = [1, "12", Data {}] +``` + +输出 YAML 为: + +```yaml +var_list: + - 1 + - "12" + - id: 1 +``` + +此外,我们可以使用 `typeof` 函数来判断 KCL 变量的类型: + +```python +schema Data1: + id: int = 1 + +schema Data2: + name: str = "name" + +data_list: [any] = [Data1 {}, Data2 {}] +data_type_list: [str] = [typeof(data) for data in data_list] +``` + +输出 YAML 为: + +```yaml +data_list: + - id: 1 + - name: name +data_type_list: + - Data1 + - Data2 +``` + +## 49. 如何通过编写 KCL 插件进行扩展? + +查看[这里](https://www.kcl-lang.io/docs/reference/plugin/overview)获得更多信息。 + +## 50. 如何在 KCL 中进行基本类型转换 + +可以使用`int()`, `float()`和`str()` 这些内置的方法来进行 `int`, `float` 和 `str` 之间的基本类型转换. + +``` +_t = 1 + +t_str: str = str(_t) # 输出的 t_str 为一个字符串 "t_str: '1'" +t_int: int = int(t_str) # 输出的 t_int 为一个整型 "t_int: 1" +t_float: float = float(t_str) # 输出的 t_float 为一个浮点型 "t_float: 1.0" +``` + +如果您想查看更多详细的关于KCL类型系统和类型转换的内容,您可以查阅 [KCL 内置类型](https://kcl-lang.io/docs/reference/lang/tour#built-in-types) 和 [KCL 类型系统](https://kcl-lang.io/docs/reference/lang/tour#type-system)。 + +## 51. 如何将列表类型的变量逐个解包到字符串中 + +KCL 的列表提供了内置的字符串格式化方法,我们可以使用 str 函数或者 str 变量的 format 函数完成此类功能,比如下面的代码 + +```python +allowed = ["development", "staging", "production"] + +schema Data: + environment: str + check: + environment in allowed, "environment must be one of {}".format(allowed) +``` + +## 52. 如何在 KCL 中输出带缩进的 JSON 字符串? + +KCL 内置了格式化 JSON 字符串的参数。 + +```python +import json +config = { + key1 = "value1" + key2 = "value2" +} +configJson = json.encode(config, ignore_private=True, indent=4) +``` + +运行此代码后,`configJson` 变量将包含一个缩进的 JSON 字符串。 + +```yaml +config: + key1: value1 + key2: value2 +configJson: |- + { + "key1": "value1", + "key2": "value2" + } +``` + +## 53. 如何计算 KCL 对象的哈希或 MD5 值? + +在 KCL 中,可以使用 crypto 库计算哈希或 MD5 值 + +```python +import crypto + +schema Person: + a: int + +aa = Person {a = 1} +bb = Person {a = 2} +cc = Person {a = 2} +aahash = crypto.md5(str(aa)) +bbhash = crypto.md5(str(bb)) +cchash = crypto.md5(str(cc)) +``` + +输出如下: + +```yaml +aa: + a: 1 +bb: + a: 2 +cc: + a: 2 +aahash: 1992c2ef118972b9c3f96c3f74cdd1a5 +bbhash: 5c71751205373815a9f2e022dd846758 +cchash: 5c71751205373815a9f2e022dd846758 +``` + +## 54. 如何对 str 列表去重? + +我们可以定义一个 `to_set` 函数对 str 列表去重,其原理是使用 KCL dict 来去除重复的值 + +```python +to_set = lambda items: [str] { + [item for item in {item = None for item in items}] +} +data = to_set(["aa", "bb", "bb", "cc"]) +dataIsUnique = isunique(data) +``` + +输出如下: + +```yaml +data: + - aa + - bb + - cc +dataIsUnique: true +``` + +## 55. 如何在变量的输出中省略具有 None 值的属性? + +在 KCL 命令行工具中,有一个内置的 disableNone 标志 (-n),启用它后 KCL 不会打印具有 None 值的属性。 + +```python +a = 1 +b = None +``` + +你可以使用以下命令运行带有 `disableNone` 功能的上述脚本(main.k) + +```shell +kcl main.k -n +``` + +输出如下: + +```yaml +a: 1 +``` + +## 56. 如何定义一个属性可以包含一个或多个不同定义 Schema? + +在 KCL 中,我们可以使用联合类型来实现这一点。例如: + +```python +schema Config: + route: EndPoint | Gateway + +schema EndPoint: + attr: str + +schema Gateway: + attr: str +``` + +## 57. 如何在 KCL 中转换字典和 Schema? + +在 KCL 中,字典是一个动态数据,没有 Schema 的检查约束。我们可以将字典转换为 Schema 以获得约束条件。我们可以直接将字典数据分配给 Schema 类型数据,KCL 运行时会自动完成类型转换并执行类型检查。 + +```python +schema Person: + name: str + age: int + check: + age > 20 + +config = { + name = "Alice" + age = 25 +} + +alice: Person = config +``` + +## 58. 请解释在 KCL 字符串和字符串插值中 'r' 前缀的关系和用法。 + +在 KCL 中,我们可以使用 `${..}` 进行字符串插值。但在某些情况下,我们不希望进行转义。因此,我们可以通过在字符串文字前添加 'r' 或 'R' 前缀来创建原始字符串。下面是一个 KCL 代码示例: + +```python +worldString = "world" +s = "Hello ${worldString}" +raw_s = r"Hello ${worldString}" +``` + +输出结果如下: + +```yaml +worldString: world +s: Hello world +raw_s: Hello ${worldString} +``` + +## 59. 在 KCL 中如何推断 lambda 函数的返回值类型? + +对于 Lambda 函数,KCL 可以自动推断函数体中的返回值类型,尽管我们也可以明确指定它。下面是一个 KCL 代码示例: + +```python +f1 = lambda t: Type1 { + Type2 {} +} # f1 的类型是 (Type1) -> Type2 +f2 = lambda t: Type1 -> Type2 { + Type2 {} +} # f2 的类型是 (Type1) -> Type2, 在这个例子中,我们显式指定了返回值类型为 Type2 +``` + +## 60. 在 KCL 中如何将列表的列表转换为单个列表? + +要将列表的列表转换为单个列表,我们可以使用 sum() 函数。例如,如果我们有多个列表,比如 `[[1,2],[3,4],[5,6]]`,我们可以使用以下 KCL 代码将这三个列表转换为单个列表: + +```python +final_list = sum([[1,2],[3,4],[5,6]], []) +``` + +上述 KCL 代码的输出如下: + +```yaml +final_list: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 +``` + +## 61. KCL 代码片段 `version: "v1" = "v1"` 是什么意思? + +这里的第一个 `"v1"` 表示变量 `version` 的类型是字符串字面类型。第二个 `"v1"` 表示变量 `version` 的默认值是 "v1"。 + +## 62. 如何定义一个 KCL Schema 校验给定 JSON/YAML 文件的内容? + +我们可以使用 kcl 的 vet 工具来校验给定 JSON 文件中的数据。例如,在下面的 data.json 文件中,我们使用以下的 KCL 文件(schema.k)来校验 age 参数。 + +data.json + +```json +[ + { + "name": "Alice", + "age": 18 + }, + { + "name": "Bob", + "age": 10 + } +] +``` + +schema.k + +```kcl +schema Person: + name: str + age: int + + check: + age >= 10 +``` + +校验 JSON 数据的命令 + +```shell +kcl vet data.json schema.k +``` + +## 63. 如何在给定 Schema 扩展数组属性的默认值? + +我们使用 += 运算符来扩展 Schema 数组属性的默认值。 + +```python +schema MyApp: + args: [str] = ["default", "args"] + +app = MyApp { + args += ["additional", "args"] +} +``` + +## 64. 可以配置 kcl 在特定路径上生成 `.kclvm` 文件夹或者其他与 kcl 编译缓存相关的目录吗? + +可以通过变量 KCL_CACHE_PATH 来更改路径。 + +在 macOS 和 Linux 上: + +可以通过向 ~/.bashrc、~/.zshrc 或类似的 shell rc 文件中添加 export 命令来设置 KCL_CACHE_PATH,或者如果您希望它只对当前会话生效,也可以直接在终端中运行它。 + +```shell +export KCL_CACHE_PATH=/tmp # 或者更改为您想要的路径 +``` + +在 Windows 上 + +可以通过命令提示符或 PowerShell 将 KCL_CACHE_PATH 设置为环境变量,以便影响所有 KCL 会话。 对于命令提示符,请使用 setx 命令来永久设置该值: + +```powershell +setx KCL_CACHE_PATH "C:\temp" /M +``` + +## 65. 如何在 KCL 中将列表连接成字符串? + +如果我们想要将给定的列表 `L = ['a', 'b', 'c']` 用特定的分隔符(如逗号 ",")连接成一个字符串,可以使用以下 KCL 代码: + +```python +S = ",".join(['a', 'b', 'c']) +``` + +## 66. 在 KCL 中是否支持 schema lambda(类方法)? + +KCL 支持为 schema 使用 lambda 定义成员函数。下面是一个相关的KCL示例代码: + +```python +schema Person: + firstName: str + lastName: str + getFullName: () -> str = lambda { + firstName + " " + lastName + } + +p = Person{ + firstName = "Alice" + lastName = "White" +} +fullName = p.getFullName() +``` + +上述 KCL 代码产生的输出: + +```yaml +p: + firstName: Alice + lastName: White +fullName: Alice White +``` + +## 67. 在 mixin 外部使用混合属性是否需要转换为 any 类型? + +需要将类型明确地添加到 schema 中即可使用混合属性。以下是一个示例代码: + +```python +schema FooBar: + mixin [ + FooBarMixin + ] + foo: str = 'foo' + bar: str = 'bar' + +protocol FooBarProtocol: + foo: str + bar: str + +mixin FooBarMixin for FooBarProtocol: + foobar: str = "${foo}.${bar}" # 带有类型注解的属性可以在模式外部访问。 + +_c = FooBar {} +foobar = _c.foobar +``` + +输出为: + +```yaml +foobar: foo.bar +``` + +## 68. 如何在 KCL 中使用 "import another-module" ? 包名中包含横线 "-" + +在 KCL 中,import 语句中使用的模块名称中只支持`_`,kcl.mod 中的包名同时支持 `-` 和 `_`,KCL 编译器会自动将包名中的 `-` 替换为 `_`。 + +```toml +# kcl.mod 中同时支持如下两种写法 +another-module = "0.1.1" +another_module = "0.1.1" +``` + +在 KCL 代码中,只支持使用如下 import 语句 + +```python +import another_module +``` + +`another-module = "0.1.1"` 和 `another_module = "0.1.1"` 是等价的, 如果同时在 `kcl.mod` 中使用这两种写法会得到一个错误。 + +## 69. KCL 语言中的 mixin 和 protocol 相当于一般编程语言中的什么特性? + +Mixin 在 KCL 中相当于其他语言中的: + +- 多重继承(Multiple Inheritance):允许一个类从多个父类继承属性和方法。 +- 接口实现(Interface Implementation):为类提供额外的方法和属性。 +- 特征(Traits):在一些支持特征的语言中(如 Rust),traits 用于定义可以被多个类型共享的行为。 + +KCL 的 mixin 允许你定义一组可重用的属性和方法,然后将它们混入到多个 schema 中,实现代码复用和行为共享。 + +Protocol 在 KCL 中类似于其他语言中的: + +- 接口(Interface):定义了一组方法签名,类型必须实现这些方法。 +- 抽象基类(Abstract Base Class):定义了一组必须被子类实现的抽象方法。 +- 协议(Protocol):在一些语言中(如 Swift),协议用于定义一组方法、属性和其他要求的蓝图。 + +KCL 的 protocol 用于定义一组规则或契约,schema 可以选择遵守这些规则。它们提供了一种方式来确保某些 schema 具有特定的结构或行为。 + +关键区别: + +- 灵活性:KCL 的 mixin 和 protocol 设计得更加灵活,适用于配置和策略定义场景。 +- 编译时检查:KCL 在编译时强制执行 mixin 和 protocol 的规则,确保类型安全。 +- 配置导向:这些特性在 KCL 中更多地用于构建和验证复杂的配置结构,而不仅仅是传统的面向对象编程。 +- 不可变性:KCL 强调不可变性,这影响了 mixin 和 protocol 的使用方式,使它们更适合于声明式配置。 diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-yaml.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-yaml.md new file mode 100644 index 000000000..4dd12c00a --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/faq-yaml.md @@ -0,0 +1,104 @@ +--- +sidebar_position: 3 +--- + +# YAML 语法 + +## 1. YAML 字符串使用单引号和双引号的区别是什么? + +- YAML 双引号字符串是唯一能够表达任意字符串的样式,通过使用 `\` 转义字符,比如使用 `\"` 转义双引号 `"`,使用 `\\` 转义反斜杠 `\`,并且可以使用单个反斜杠 `\` 作为双引号字符串的续行符 +- YAML 单引号字符串与 YAML 双引号字符串不同的是可以自由地使用 `\` 和 `"` 而不需要转义,但是使用两个单引号 `''` 转义单引号 `'` 字符 + +比如对于如下的例子,三个字符串变量的内容是相同的 + +```yaml +string1: 'here '' s to "quotes"' +string2: 'here''s to "quotes"' +string3: here's to "quotes" +``` + +因此,KCL 输出 YAML 字符串的策略是当字符串内容出现单引号时,优先输出无引号字符串或双引号字符串,其他情况输出单引号字符串以避免理解上的负担。 + +更多细节可参考: [YAML 规范 v1.2](https://yaml.org/spec/1.2.1/) + +## 2. YAML 中出现的 | - + > 等符号是什么含义? + +在使用 KCL 多行字符串(使用三引号括起来的字符串),输出的 YAML 经常会携带一些特殊的记号,如 `|`,`-`,`+` 和 `>` 等,这些记号通常为 YAML 多行字符串的表示方法,比如对于如下 KCL 代码: + +```python +data = """This is a KCL multi line string (the first line) +This is a KCL multi line string (the second line) +This is a KCL multi line string (the third line) + + +""" +var = 1 +``` + +输出 YAML 为: + +```yaml +data: |+ + This is a KCL multi line string (the first line) + This is a KCL multi line string (the second line) + This is a KCL multi line string (the third line) + + +var: 1 +``` + +- `|` 表示**块字符串样式**,用于表示一个多行字符串,其中的所有换行符都表示字符串真实的换行; +- `>` 表示**块折叠样式**,在其中所有的换行符将被空格替换; +- `+` 和 `-` 用于控制在字符串末尾使用换行符的情况。默认情况为字符串末尾保留单个换行符,如果要删除所有换行符,可以在样式指示符 `|` 或 `>` 后面放置一个 `-` 来完成,如果要保留末尾的换行符,则需要在 `|` 或 `>` 后面放置一个 `+` + +更多细节可参考: [YAML 多行字符串](https://yaml-multiline.info/) 和 [YAML 规范 v1.2](https://yaml.org/spec/1.2.1/) + +## 3. YAML 中在 | - + > 等符号之后出现的数字是什么含义? + +数字表示 YAML 当中的**显式缩进指示符**。对于 YAML 中的长字符串,YAML 通常第一个非空行确定字符串的缩进级别,而当第一个非空行前面具有非前导字符时,比如换行符,YAML 要求必须使用**显式缩进指示符**来指定内容的缩进级别,比如 `|2` 和 `|1` 等 + +比如对于如下 KCL 代码: + +```python +longStringStartWithNewline = """ +This is the second line +This is the third line +""" + +``` + +```yaml +longStringStartWithNewline: |2 + + This is the second line + This is the third line +``` + +如果不需要长字符串开头的空行或换行符,则可以以如下两种方式进行 KCL 长字符串书写 + +- 长字符串从第 1 行开始书写 + +```python +longString = """This is the second line +This is the third line +""" +``` + +- 使用续行符 + +```python +longString = """\ +This is the second line +This is the third line +""" +``` + +以上两种方式输出的 YAML 均为: + +```yaml +longString: | + This is the second line + This is the third line +``` + +更多细节可参考: [YAML 规范 v1.2](https://yaml.org/spec/1.2.1/) diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/support.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/support.md new file mode 100644 index 000000000..9aab81784 --- /dev/null +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.12/user_docs/support/support.md @@ -0,0 +1,7 @@ +# 常见问答 + +KCL 安装、使用过程中遇到的常见问题,包括基本概念解释、KCL 语法、KCL 语言设计、命令行工具和 YAML 等常见问题。 + +import DocCardList from '@theme/DocCardList'; + + diff --git a/package-lock.json b/package-lock.json index b1c409e87..98985ef2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "kcl-website", - "version": "0.11.0", + "version": "0.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kcl-website", - "version": "0.11.0", + "version": "0.12.0", "dependencies": { "@cmfcmf/docusaurus-search-local": "^1.1.0", "@docusaurus/core": "2.4.1", diff --git a/package.json b/package.json index 555f01ab1..300696a2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kcl-website", - "version": "0.11.0", + "version": "0.12.0", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/src/components/Form/index.tsx b/src/components/Form/index.tsx index 613bb86b5..934fc7fac 100644 --- a/src/components/Form/index.tsx +++ b/src/components/Form/index.tsx @@ -206,7 +206,12 @@ export const Form = ({ fireInput }: { fireInput?: () => void }) => { placeholder="Your email address..." disabled={formState === STATES.LOADING || formState === STATES.SUCCESS} onChange={onChange} - style={{ width: WIDTH, maxWidth: MAX_WIDTH, minHeight: HEIGHT, textOverflow: "ellipsis" }} + style={{ + width: WIDTH, + maxWidth: MAX_WIDTH, + minHeight: HEIGHT, + textOverflow: "ellipsis", + }} />