├── .eslintignore ├── .github └── workflows │ ├── ci.yml │ └── codeql-analysis.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .vscode └── settings.json ├── AUTHORS.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── eslint.config.js ├── example-1.gif ├── example-1.mp4 ├── jest.config.js ├── package-lock.json ├── package.json ├── packages ├── schema-dts-gen │ ├── LICENSE │ ├── README.md │ ├── bin │ │ └── schema-dts-gen.js │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── cli │ │ │ ├── args.ts │ │ │ ├── cli.ts │ │ │ └── internal │ │ │ │ └── main.ts │ │ ├── dep-types │ │ │ ├── rehype-minify-whitespace.d.ts │ │ │ └── remark-wiki-link.d.ts │ │ ├── index.ts │ │ ├── logging │ │ │ └── index.ts │ │ ├── transform │ │ │ ├── toClass.ts │ │ │ ├── toEnum.ts │ │ │ ├── toProperty.ts │ │ │ └── transform.ts │ │ ├── triples │ │ │ ├── operators.ts │ │ │ ├── reader.ts │ │ │ ├── term_utils.ts │ │ │ └── wellKnown.ts │ │ ├── ts │ │ │ ├── action_constraints.ts │ │ │ ├── class.ts │ │ │ ├── context.ts │ │ │ ├── enum.ts │ │ │ ├── helper_types.ts │ │ │ ├── property.ts │ │ │ └── util │ │ │ │ ├── arrayof.ts │ │ │ │ ├── comments.ts │ │ │ │ ├── names.ts │ │ │ │ └── union.ts │ │ ├── tsconfig.json │ │ └── util │ │ │ └── assert.ts │ ├── test │ │ ├── baselines │ │ │ ├── category_test.ts │ │ │ ├── comments_test.ts │ │ │ ├── data_type_union_test.ts │ │ │ ├── default_ontology_test.ts │ │ │ ├── deprecated_objects_test.ts │ │ │ ├── duplicate_comments_test.ts │ │ │ ├── enum_skipped_test.ts │ │ │ ├── inheritance_multiple_test.ts │ │ │ ├── inheritance_one_test.ts │ │ │ ├── invalid_schemas_test.ts │ │ │ ├── must_define_datatype_test.ts │ │ │ ├── nested_datatype_test.ts │ │ │ ├── nodeprecated_objects_test.ts │ │ │ ├── owl_mixed_basic_test.ts │ │ │ ├── property_edge_cases_test.ts │ │ │ ├── quantities_test.ts │ │ │ ├── role_inheritance_test.ts │ │ │ ├── role_simple_test.ts │ │ │ ├── simple_test.ts │ │ │ ├── sorted_enum_test.ts │ │ │ ├── sorted_props_test.ts │ │ │ ├── sorted_proptypes_test.ts │ │ │ ├── stringlike_http_test.ts │ │ │ ├── stringlike_https_test.ts │ │ │ ├── surgical_procedure_3_4_test.ts │ │ │ ├── surgical_procedure_3_4_v2_test.ts │ │ │ ├── surgical_procedure_test.ts │ │ │ ├── transitive_class_test.ts │ │ │ ├── unknown_wellknown_test.ts │ │ │ └── url_test.ts │ │ ├── cli │ │ │ ├── args_logmessages_test.ts │ │ │ └── args_test.ts │ │ ├── helpers │ │ │ ├── async.ts │ │ │ ├── main_driver.ts │ │ │ └── make_class.ts │ │ ├── logging │ │ │ └── index_test.ts │ │ ├── triples │ │ │ ├── reader_test.ts │ │ │ └── wellKnown_test.ts │ │ ├── ts │ │ │ ├── class_test.ts │ │ │ ├── context_test.ts │ │ │ ├── enum_test.ts │ │ │ ├── names_test.ts │ │ │ └── property_test.ts │ │ └── tsconfig.json │ └── tsconfig.json └── schema-dts │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── test │ ├── easy.ts │ ├── graph.ts │ ├── tsconfig.json │ ├── values.ts │ ├── withactionconstraints.ts │ └── withcontext.ts │ └── tsconfig.json └── tsconfig-base.json /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage 3 | jest.config.js 4 | schema-dts/lib/ 5 | schema-dts/dist/ 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [22.x, 23.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v2 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm ci 25 | - run: npm run build 26 | - run: npm test 27 | - name: Coveralls - schema-dts-gen 28 | uses: coverallsapp/github-action@master 29 | if: ${{ matrix.node-version == '22.x' }} 30 | with: 31 | github-token: ${{ secrets.GITHUB_TOKEN }} 32 | path-to-lcov: ./packages/schema-dts-gen/coverage/lcov.info 33 | base-path: packages/schema-dts-gen 34 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [ main ] 9 | schedule: 10 | - cron: '17 11 * * 6' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | language: [ 'javascript' ] 25 | 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v2 29 | 30 | # Initializes the CodeQL tools for scanning. 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v2 33 | with: 34 | languages: ${{ matrix.language }} 35 | # If you wish to specify custom queries, you can do so here or in a config file. 36 | # By default, queries listed here will override any specified in a config file. 37 | # Prefix the list here with "+" to use these queries and those in the config file. 38 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 39 | 40 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 41 | # If this step fails, then you should remove it and run the build manually (see below) 42 | - name: Autobuild 43 | uses: github/codeql-action/autobuild@v2 44 | 45 | # ℹ️ Command-line programs to run using the OS shell. 46 | # 📚 https://git.io/JvXDl 47 | 48 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 49 | # and modify them (or add more) to build your code if your project 50 | # uses a compiled language 51 | 52 | #- run: | 53 | # make bootstrap 54 | # make release 55 | 56 | - name: Perform CodeQL Analysis 57 | uses: github/codeql-action/analyze@v2 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | built 3 | dist/ 4 | .nyc_output/ 5 | coverage/ 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | packages/schema-dts/lib/ 4 | .nyc_output/ 5 | coverage/ 6 | .github/ 7 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "proseWrap": "always", 3 | "singleQuote": true, 4 | "bracketSpacing": false, 5 | "arrowParens": "avoid" 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.tabSize": 2, 4 | "eslint.options": { 5 | "overrideConfigFile": "./.eslintrc.cjs" 6 | }, 7 | "editor.defaultFormatter": "esbenp.prettier-vscode", 8 | "[typescript]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "typescript.tsdk": "node_modules/typescript/lib" 12 | } 13 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | Schema DTS and the Schema TypeScript Generator are maintained by: 2 | 3 | - [Eyas Sharaiha](https://eyas.sh/) 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows 28 | [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). 29 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import jsdoc from 'eslint-plugin-jsdoc'; 2 | import importPlugin from 'eslint-plugin-import'; 3 | import prettierConfig from 'eslint-config-prettier'; 4 | import stylistic from '@stylistic/eslint-plugin'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | export default tseslint.config( 8 | tseslint.configs.recommendedTypeChecked, 9 | prettierConfig, 10 | { 11 | languageOptions: { 12 | parserOptions: { 13 | projectService: true, 14 | tsconfigRootDir: [import.meta.dirname], 15 | }, 16 | }, 17 | }, 18 | { 19 | files: ['**/*.ts'], 20 | plugins: {jsdoc, import: importPlugin, '@stylistic': stylistic}, 21 | rules: { 22 | '@typescript-eslint/array-type': [ 23 | 'error', 24 | { 25 | default: 'array-simple', 26 | }, 27 | ], 28 | '@typescript-eslint/no-restricted-types': [ 29 | 'error', 30 | { 31 | types: { 32 | Object: { 33 | fixWith: 'object', 34 | }, 35 | String: { 36 | fixWith: 'string', 37 | }, 38 | Number: { 39 | fixWith: 'number', 40 | }, 41 | Boolean: { 42 | fixWith: 'boolean', 43 | }, 44 | }, 45 | }, 46 | ], 47 | '@typescript-eslint/naming-convention': [ 48 | 'error', 49 | { 50 | selector: 'default', 51 | format: ['camelCase'], 52 | leadingUnderscore: 'allow', 53 | trailingUnderscore: 'allow', 54 | }, 55 | { 56 | selector: 'variable', 57 | format: ['PascalCase', 'camelCase', 'UPPER_CASE'], 58 | modifiers: ['const'], 59 | leadingUnderscore: 'allow', 60 | trailingUnderscore: 'allow', 61 | }, 62 | { 63 | selector: 'variableLike', 64 | format: ['PascalCase', 'camelCase'], 65 | filter: {regex: '^_$', match: false}, 66 | }, 67 | { 68 | selector: 'memberLike', 69 | format: ['camelCase', 'PascalCase'], 70 | }, 71 | { 72 | selector: 'memberLike', 73 | modifiers: ['private'], 74 | format: ['camelCase', 'PascalCase'], 75 | leadingUnderscore: 'allow', 76 | }, 77 | { 78 | selector: 'typeLike', 79 | format: ['PascalCase'], 80 | }, 81 | { 82 | selector: ['typeProperty', 'objectLiteralProperty'], 83 | format: null, 84 | }, 85 | ], 86 | '@typescript-eslint/consistent-type-assertions': 'error', 87 | '@typescript-eslint/consistent-type-definitions': 'error', 88 | '@typescript-eslint/explicit-member-accessibility': [ 89 | 'error', 90 | { 91 | accessibility: 'no-public', 92 | }, 93 | ], 94 | '@stylistic/member-delimiter-style': [ 95 | 'error', 96 | { 97 | multiline: { 98 | delimiter: 'semi', 99 | requireLast: true, 100 | }, 101 | singleline: { 102 | delimiter: 'semi', 103 | requireLast: false, 104 | }, 105 | }, 106 | ], 107 | '@typescript-eslint/no-explicit-any': 'error', 108 | '@typescript-eslint/no-inferrable-types': 'error', 109 | '@typescript-eslint/no-namespace': 'error', 110 | '@typescript-eslint/no-require-imports': 'error', 111 | '@typescript-eslint/no-unused-expressions': [ 112 | 'error', 113 | {allowShortCircuit: true}, 114 | ], 115 | '@typescript-eslint/no-unused-vars': [ 116 | 'error', 117 | { 118 | argsIgnorePattern: '^_', 119 | caughtErrorsIgnorePattern: '^_', 120 | destructuredArrayIgnorePattern: '^_', 121 | varsIgnorePattern: '^_', 122 | ignoreRestSiblings: true, 123 | }, 124 | ], 125 | '@typescript-eslint/triple-slash-reference': 'error', 126 | '@stylistic/semi': ['error', 'always'], 127 | 'arrow-body-style': 'error', 128 | curly: ['error', 'multi-line'], 129 | 'default-case': 'error', 130 | eqeqeq: ['error', 'smart'], 131 | 'guard-for-in': 'error', 132 | 'id-denylist': [ 133 | 'error', 134 | 'any', 135 | 'Number', 136 | 'number', 137 | 'String', 138 | 'string', 139 | 'Boolean', 140 | 'boolean', 141 | 'Undefined', 142 | ], 143 | 'id-match': 'error', 144 | 'import/no-default-export': 'error', 145 | 'jsdoc/check-alignment': 'error', 146 | 'new-parens': 'error', 147 | 'no-debugger': 'error', 148 | 'no-duplicate-case': 'error', 149 | 'no-new-wrappers': 'error', 150 | 'no-return-await': 'error', 151 | 'no-throw-literal': 'error', 152 | 'no-underscore-dangle': 'off', 153 | 'no-unsafe-finally': 'error', 154 | 'no-unused-expressions': ['error', {allowShortCircuit: true}], 155 | 'no-unused-labels': 'error', 156 | 'no-var': 'error', 157 | 'object-shorthand': 'error', 158 | 'prefer-arrow-callback': 'error', 159 | 'prefer-const': 'error', 160 | radix: 'error', 161 | 'use-isnan': 'error', 162 | }, 163 | settings: {}, 164 | }, 165 | ); 166 | -------------------------------------------------------------------------------- /example-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/schema-dts/966fffa899ef4d70da453268ccf87f75149cd52d/example-1.gif -------------------------------------------------------------------------------- /example-1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/schema-dts/966fffa899ef4d70da453268ccf87f75149cd52d/example-1.mp4 -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | projects: ['/packages/*'], 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monorepo", 3 | "private": "true", 4 | "author": "Eyas Sharaiha (https://eyas.sh/)", 5 | "maintainers": [ 6 | "Eyas Sharaiha (https://eyas.sh/)" 7 | ], 8 | "devDependencies": { 9 | "@jest/globals": "^29.7.0", 10 | "@stylistic/eslint-plugin": "^4.2.0", 11 | "eslint": "^9.21.0", 12 | "eslint-config-prettier": "^10.0.2", 13 | "eslint-plugin-import": "^2.31.0", 14 | "eslint-plugin-jsdoc": "^50.6.17", 15 | "jest": "^29.7.0", 16 | "prettier": "^3.5.3", 17 | "rimraf": "^6.0.1", 18 | "ts-jest": "^29.3.4", 19 | "typescript": "^5.8.2", 20 | "typescript-eslint": "^8.32.1" 21 | }, 22 | "overrides": { 23 | "typescript-eslint": { 24 | "typescript": "$typescript" 25 | }, 26 | "@typescript-eslint/eslint-plugin": { 27 | "typescript": "$typescript" 28 | }, 29 | "@typescript-eslint/parser": { 30 | "typescript": "$typescript" 31 | } 32 | }, 33 | "engines": { 34 | "node": ">=14.0.0", 35 | "npm": ">=7.0.0" 36 | }, 37 | "engineStrict": true, 38 | "nyc": { 39 | "extension": [ 40 | ".ts", 41 | ".tsx" 42 | ], 43 | "exclude": [ 44 | "**/*.d.ts", 45 | "dist/**/*", 46 | "coverage/**/*", 47 | "test/**/*", 48 | "src/cli/cli.ts" 49 | ], 50 | "reporter": [ 51 | "html" 52 | ], 53 | "all": true 54 | }, 55 | "homepage": "https://opensource.google/projects/schema-dts", 56 | "bugs": "https://github.com/google/schema-dts/issues", 57 | "repository": "github:google/schema-dts", 58 | "license": "Apache-2.0", 59 | "scripts": { 60 | "clean": "rimraf \"packages/**/dist\" \"packages/**/*.tsbuildinfo\" packages/schema-dts/lib/*", 61 | "build": "npm run build --workspaces", 62 | "lint:prettier": "prettier --check .", 63 | "lint:eslint": "npm run lint:eslint --workspaces --if-present --", 64 | "lint": "npm run lint:eslint && npm run lint:prettier", 65 | "fix:prettier": "prettier --write .", 66 | "fix:eslint": "npm run lint:eslint -- --fix ", 67 | "fix": "npm run fix:eslint && npm run fix:prettier", 68 | "test": "npm run lint && npm run test --workspaces", 69 | "coverage_on_travis": "npm run coverage_on_travis -w schema-dts-gen", 70 | "pkg": "npm run clean && npm run build" 71 | }, 72 | "type": "module", 73 | "workspaces": [ 74 | "packages/schema-dts-gen", 75 | "packages/schema-dts" 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/google/schema-dts/actions/workflows/ci.yml/badge.svg)](https://github.com/google/schema-dts/actions/workflows/ci.yml) 2 | [![Coverage Status](https://coveralls.io/repos/github/google/schema-dts/badge.svg?branch=main)](https://coveralls.io/github/google/schema-dts?branch=main) 3 | [![schema-dts-gen version](https://badge.fury.io/js/schema-dts-gen.svg)](https://www.npmjs.com/package/schema-dts-gen) 4 | 5 | # schema-dts-gen 6 | 7 | JSONG-LD TypeScript typing generator for Schema.org vocabulary & related 8 | ontologies. 9 | 10 | **schema-dts-gen** is the generator that powers 11 | [schema-dts](https://www.npmjs.com/package/schema-dts). It creates TypeScript 12 | definitions for JSON-LD conforming to a given ontology. 13 | 14 | Note: This is not an officially supported Google product. 15 | 16 | ## Usage 17 | 18 | To use the typings for your project, simply add the 19 | [`schema-dts`](https://www.npmjs.com/package/schema-dts) NPM package to your 20 | project: 21 | 22 | ```command 23 | npm install schema-dts-gen 24 | npx schema-dts-gen --ontology=https://schema.org/version/latest/schemaorg-all-https.nt 25 | ``` 26 | 27 | Command line usage: 28 | 29 | - **Specify your ontology** 30 | 31 | - Specify **`--ontology`**: An HTTPs URL to an .nt NTriple file declaring your 32 | ontology. 33 | 34 | Must be compatible with Schema.org, including the Schema.org `DataType`s and 35 | specifying a top-level `Thing` type. 36 | 37 | - **`--context`**: Defaults to `https://schema.org`, the value or values to be 38 | used with the `"@context"` property. 39 | 40 | Can be either a single URL, or a comma separated list of two or more name:URL 41 | pairs. 42 | 43 | The context affects names of string properties in types, as well as the values 44 | of an object's `"@type"`. 45 | 46 | - **`--deprecated`**/**`--nodeprecated`**: Whether or not to include deprecated 47 | Schema.org types and properties. When included, these types will still be 48 | marked with `@deprecated` JSDOC tags. 49 | 50 | - **`--verbose`**: Outputs additional logs and debugging notes to stderr. 51 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/bin/schema-dts-gen.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import '../dist/src/cli/cli.js'; 3 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/jest.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | preset: 'ts-jest/presets/default-esm', // or other ESM presets 3 | moduleNameMapper: { 4 | '^(\\.{1,2}/.*)\\.js$': '$1', 5 | }, 6 | prettierPath: null, 7 | testEnvironment: 'node', 8 | testMatch: ['**/*_test.[jt]s?(x)'], 9 | testPathIgnorePatterns: ['/node_modules/', '/dist/'], 10 | collectCoverage: true, 11 | coveragePathIgnorePatterns: ['/node_modules/', '/dist/'], 12 | // We don't need this because we use Coveralls 'base-dir' 13 | // coverageReporters: ['json', ['lcov', {projectRoot: '../../'}], 'text'], 14 | }; 15 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "schema-dts-gen", 3 | "version": "1.1.5", 4 | "displayName": "schema-dts Generator", 5 | "description": "Generate TypeScript Definitions for Schema.org Schema", 6 | "author": "Eyas Sharaiha (https://eyas.sh/)", 7 | "maintainers": [ 8 | "Eyas Sharaiha (https://eyas.sh/)" 9 | ], 10 | "contributors": [ 11 | "Eyas Sharaiha (https://eyas.sh/)" 12 | ], 13 | "files": [ 14 | "dist/src/**/*" 15 | ], 16 | "types": "./dist/src/index.d.ts", 17 | "main": "./dist/src/index.js", 18 | "bin": { 19 | "schema-dts-gen": "bin/schema-dts-gen.js" 20 | }, 21 | "sideEffects": false, 22 | "type": "module", 23 | "devDependencies": { 24 | "@jest/globals": "^29.4.3", 25 | "@types/argparse": "^2.0.17", 26 | "@types/array.prototype.flatmap": "^1.2.6", 27 | "@types/jest": "^29.5.14", 28 | "@types/n3": "^1.21.1", 29 | "@types/node": "^22.13.8", 30 | "@types/unist": "^3.0.3", 31 | "cross-env": "^7.0.3" 32 | }, 33 | "dependencies": { 34 | "argparse": "^2.0.1", 35 | "n3": "^1.23.1", 36 | "rehype-minify-whitespace": "^6.0.2", 37 | "rehype-parse": "^9.0.1", 38 | "rehype-raw": "^7.0.0", 39 | "remark-parse": "^11.0.0", 40 | "remark-rehype": "^11.1.1", 41 | "remark-wiki-link": "^2.0.1", 42 | "unified": "^11.0.5" 43 | }, 44 | "engines": { 45 | "node": ">=14.0.0" 46 | }, 47 | "engineStrict": true, 48 | "peerDependencies": { 49 | "typescript": ">=4.9.5" 50 | }, 51 | "nyc": { 52 | "extension": [ 53 | ".ts", 54 | ".tsx" 55 | ], 56 | "exclude": [ 57 | "**/*.d.ts", 58 | "dist/**/*", 59 | "coverage/**/*", 60 | "test/**/*", 61 | "src/cli/cli.ts" 62 | ], 63 | "reporter": [ 64 | "html" 65 | ], 66 | "all": true 67 | }, 68 | "keywords": [ 69 | "typescript", 70 | "tsd", 71 | "dts", 72 | "schema.org", 73 | "Semantic Web", 74 | "semantic-web", 75 | "Linked Data", 76 | "linked-data", 77 | "jsonld", 78 | "JSON-LD", 79 | "structured data", 80 | "structured-data" 81 | ], 82 | "homepage": "https://opensource.google/projects/schema-dts", 83 | "bugs": "https://github.com/google/schema-dts/issues", 84 | "repository": { 85 | "type": "git", 86 | "url": "https://github.com/google/schema-dts.git", 87 | "directory": "packages/schema-dts-gen" 88 | }, 89 | "license": "Apache-2.0", 90 | "scripts": { 91 | "lint:eslint": "eslint src/**/*.ts test/**/*.ts", 92 | "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage", 93 | "build": "tsc -b" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/cli/args.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {ArgumentParser} from 'argparse'; 18 | 19 | export interface Options { 20 | /** HTTPS URL to an .nt file defining a custom ontology. */ 21 | ontology: string; 22 | file: string | undefined; 23 | verbose: boolean; 24 | deprecated: boolean; 25 | context: string; 26 | } 27 | 28 | // argparse forces snake_case on us. 29 | /* eslint @typescript-eslint/naming-convention: 0 */ 30 | /* eslint camelcase: 0 */ 31 | export function ParseFlags(args?: string[]): Options { 32 | const parser = new ArgumentParser({ 33 | add_help: true, 34 | description: 'schema-dts generator', 35 | }); 36 | 37 | const verbose = parser.add_mutually_exclusive_group({required: false}); 38 | verbose.add_argument('--verbose', { 39 | default: false, 40 | action: 'store_true', 41 | dest: 'verbose', 42 | }); 43 | verbose.add_argument('--noverbose', {action: 'store_false', dest: 'verbose'}); 44 | 45 | parser.add_argument('--schema', { 46 | default: undefined, 47 | help: 'Deprecated. Please use --ontology instead.', 48 | metavar: 'version', 49 | dest: 'schema', 50 | type: DeprecatedValue, 51 | }); 52 | parser.add_argument('--layer', { 53 | default: undefined, 54 | help: 'Deprecated. Please use --ontology instead.', 55 | metavar: 'name_of_file', 56 | dest: 'layer', 57 | type: DeprecatedValue, 58 | }); 59 | parser.add_argument('--context', { 60 | default: 'https://schema.org', 61 | help: 62 | 'Single URL or comma-separated key:value pairs defining the ' + 63 | "intended '@context' for the generated JSON-LD typings. " + 64 | "By default, this is 'https://schema.org`. Alternatively: " + 65 | '--context=rdf:http://www.w3.org/2000/01/rdf-schema,' + 66 | 'schema:https://schema.org\n' + 67 | "would result in 'rdf:' being a prefix for any RDF Schema " + 68 | "property, and 'schema:' being a prefix for any Schema.org property.", 69 | metavar: 'key1:url,key2:url,...', 70 | dest: 'context', 71 | }); 72 | parser.add_argument('--ontology', { 73 | default: 'https://schema.org/version/latest/schemaorg-all-https.nt', 74 | help: 75 | 'HTTPS URL to a custom .nt file defining an entirely self-' + 76 | 'sufficient schema. The schema must still be described in terms of ' + 77 | "Schema.org DataTypes, as well as rdf/rdfs concepts like 'type', " + 78 | "'domainIncludes', and 'rangeIncludes'.", 79 | metavar: 'https://url.to/schema.nt', 80 | dest: 'ontology', 81 | }); 82 | parser.add_argument('--file', { 83 | default: undefined, 84 | help: 'file path to a .nt file, for using a local ontology file', 85 | dest: 'file', 86 | }); 87 | 88 | const deprecated = parser.add_mutually_exclusive_group({required: false}); 89 | deprecated.add_argument('--deprecated', { 90 | default: true, 91 | help: 'Include deprecated Classes and Properties.', 92 | action: 'store_true', 93 | dest: 'deprecated', 94 | }); 95 | deprecated.add_argument('--nodeprecated', { 96 | help: 'Skip deprecated Classes and Properties.', 97 | action: 'store_false', 98 | dest: 'deprecated', 99 | }); 100 | return parser.parse_args(args) as Options; 101 | } 102 | 103 | function DeprecatedValue(_: unknown) { 104 | throw new Error('This command line argument is deprecated.'); 105 | } 106 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/cli/cli.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {main} from './internal/main.js'; 17 | 18 | function write(content: string) { 19 | process.stdout.write(content, 'utf-8'); 20 | } 21 | 22 | main(write) 23 | .then(() => { 24 | process.exit(); 25 | }) 26 | .catch(e => { 27 | console.error(e); 28 | process.abort(); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/cli/internal/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Store} from 'n3'; 18 | import {Log, SetOptions} from '../../logging/index.js'; 19 | import {WriteDeclarations} from '../../transform/transform.js'; 20 | import {load, loadFile} from '../../triples/reader.js'; 21 | import {Context} from '../../ts/context.js'; 22 | 23 | import {ParseFlags} from '../args.js'; 24 | 25 | export async function main(write: (s: string) => void, args?: string[]) { 26 | const options = ParseFlags(args); 27 | SetOptions(options); 28 | 29 | const ontologyUrl = options.ontology; 30 | const filePath = options.file; 31 | let result: Store; 32 | 33 | if (filePath) { 34 | Log(`Loading Ontology from path: ${filePath}`); 35 | result = await loadFile(filePath); 36 | } else { 37 | Log(`Loading Ontology from URL: ${ontologyUrl}`); 38 | result = await load(ontologyUrl); 39 | } 40 | const context = Context.Parse(options.context); 41 | await WriteDeclarations(result, options.deprecated, context, write); 42 | } 43 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/dep-types/rehype-minify-whitespace.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'rehype-minify-whitespace' { 2 | // eslint-disable-next-line import/no-default-export 3 | export default function minifyWhitespace(): void; 4 | } 5 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/dep-types/remark-wiki-link.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'remark-wiki-link' { 2 | // eslint-disable-next-line import/no-default-export 3 | export default function wikiLinkPlugin(opts?: { 4 | permalinks?: string; 5 | pageResolver?: (l: string) => string[]; 6 | hrefTemplate?: (l: string) => string; 7 | wikiLinkClassName?: string; 8 | newClassName?: string; 9 | aliasDivider?: string; 10 | }): void; 11 | } 12 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Public Declarations only: 18 | export {WriteDeclarations} from './transform/transform.js'; 19 | 20 | export {load as loadTriples} from './triples/reader.js'; 21 | export * from './triples/term_utils.js'; 22 | export * from './triples/wellKnown.js'; 23 | 24 | export * from './ts/class.js'; 25 | export * from './ts/enum.js'; 26 | export * from './ts/property.js'; 27 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/logging/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | let verbose = false; 18 | let logger = console.error; 19 | 20 | export function SetOptions(options: {verbose: boolean}): void { 21 | verbose = options.verbose; 22 | } 23 | 24 | export function Log(message: string): void { 25 | if (verbose) { 26 | logger(message); 27 | } 28 | } 29 | 30 | export function SetLogger(newLogger: (msg: string) => void) { 31 | const previousLogger = logger; 32 | function RestoreLogger() { 33 | logger = previousLogger; 34 | } 35 | logger = newLogger; 36 | return RestoreLogger; 37 | } 38 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/transform/toClass.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Log} from '../logging/index.js'; 18 | 19 | import { 20 | IsDirectlyNamedClass, 21 | IsDataType, 22 | ClassIsDataType, 23 | IsSubclass, 24 | TypedTopic, 25 | } from '../triples/wellKnown.js'; 26 | import { 27 | AliasBuiltin, 28 | Class, 29 | ClassMap, 30 | DataTypeUnion, 31 | RoleBuiltin, 32 | } from '../ts/class.js'; 33 | import {assert, assertIs} from '../util/assert.js'; 34 | 35 | import type {Quad} from 'n3'; 36 | import {NamedNode} from 'n3'; 37 | import {shortStr} from '../index.js'; 38 | 39 | function toClass(cls: Class, topic: TypedTopic, map: ClassMap): Class { 40 | const rest: Quad[] = []; 41 | 42 | for (const value of topic.quads) { 43 | const added = cls.add(value, map); 44 | if (!added) rest.push(value); 45 | } 46 | 47 | if (rest.length > 0) { 48 | Log( 49 | `Class ${shortStr(cls.subject)}: Did not add [${rest 50 | .map(r => `(${shortStr(r.predicate)} ${shortStr(r.object)})`) 51 | .join(',')}]`, 52 | ); 53 | } 54 | return cls; 55 | } 56 | 57 | function buildAlias(name: string, alias: string): AliasBuiltin[] { 58 | return [ 59 | new AliasBuiltin( 60 | new NamedNode(`http://schema.org/${name}`), 61 | AliasBuiltin.Alias(alias), 62 | ), 63 | new AliasBuiltin( 64 | new NamedNode(`https://schema.org/${name}`), 65 | AliasBuiltin.Alias(alias), 66 | ), 67 | ]; 68 | } 69 | const wellKnownTypes = [ 70 | ...buildAlias('Text', 'string'), 71 | // IMPORTANT: In the future, if possible, we should have: `${number}` in Float only, 72 | // an integer string literal in Integer only, and Number becomes simply Float|Integer. 73 | new AliasBuiltin( 74 | new NamedNode('http://schema.org/Number'), 75 | AliasBuiltin.Alias('number'), 76 | AliasBuiltin.NumberStringLiteral(), 77 | ), 78 | new AliasBuiltin( 79 | new NamedNode('https://schema.org/Number'), 80 | AliasBuiltin.Alias('number'), 81 | AliasBuiltin.NumberStringLiteral(), 82 | ), 83 | ...buildAlias('Time', 'string'), 84 | ...buildAlias('Date', 'string'), 85 | ...buildAlias('DateTime', 'string'), 86 | ...buildAlias('Boolean', 'boolean'), 87 | new RoleBuiltin(new NamedNode('http://schema.org/Role')), 88 | new RoleBuiltin(new NamedNode('http://schema.org/OrganizationRole')), 89 | new RoleBuiltin(new NamedNode('http://schema.org/EmployeeRole')), 90 | new RoleBuiltin(new NamedNode('http://schema.org/LinkRole')), 91 | new RoleBuiltin(new NamedNode('http://schema.org/PerformanceRole')), 92 | new RoleBuiltin(new NamedNode('https://schema.org/Role')), 93 | new RoleBuiltin(new NamedNode('https://schema.org/OrganizationRole')), 94 | new RoleBuiltin(new NamedNode('https://schema.org/EmployeeRole')), 95 | new RoleBuiltin(new NamedNode('https://schema.org/LinkRole')), 96 | new RoleBuiltin(new NamedNode('https://schema.org/PerformanceRole')), 97 | ]; 98 | 99 | // Should we allow 'string' to be a valid type for all values of this type? 100 | const wellKnownStrings = [ 101 | new NamedNode('http://schema.org/Quantity'), 102 | new NamedNode('http://schema.org/EntryPoint'), 103 | new NamedNode('http://schema.org/Organization'), 104 | new NamedNode('http://schema.org/Person'), 105 | new NamedNode('http://schema.org/Place'), 106 | new NamedNode('https://schema.org/Quantity'), 107 | new NamedNode('https://schema.org/EntryPoint'), 108 | new NamedNode('https://schema.org/Organization'), 109 | new NamedNode('https://schema.org/Person'), 110 | new NamedNode('https://schema.org/Place'), 111 | ]; 112 | 113 | function ForwardDeclareClasses(topics: readonly TypedTopic[]): ClassMap { 114 | const classes = new Map(); 115 | const dataType = new DataTypeUnion( 116 | new NamedNode('http://schema.org/DataType'), 117 | [], 118 | ); 119 | 120 | for (const topic of topics) { 121 | if (IsDataType(topic.subject)) { 122 | classes.set(topic.subject.value, dataType); 123 | continue; 124 | } else if (!IsDirectlyNamedClass(topic) && !IsSubclass(topic)) continue; 125 | 126 | const wk = wellKnownTypes.find(wk => wk.subject.equals(topic.subject)); 127 | if (ClassIsDataType(topic)) { 128 | assert( 129 | wk, 130 | `${topic.subject.value} must have corresponding well-known type.`, 131 | ); 132 | dataType.wk.push(wk); 133 | 134 | wk['_isDataType'] = true; 135 | } 136 | 137 | assertIs(topic.subject, (s): s is NamedNode => s.termType === 'NamedNode'); 138 | const cls = wk || new Class(topic.subject); 139 | const allowString = wellKnownStrings.some(wks => wks.equals(topic.subject)); 140 | if (allowString) cls.addTypedef(AliasBuiltin.Alias('string')); 141 | if (IsDirectlyNamedClass(topic)) cls.markAsExplicitClass(); 142 | 143 | classes.set(topic.subject.value, cls); 144 | } 145 | 146 | return classes; 147 | } 148 | 149 | function BuildClasses(topics: readonly TypedTopic[], classes: ClassMap) { 150 | for (const topic of topics) { 151 | if (!IsDirectlyNamedClass(topic) && !IsSubclass(topic)) continue; 152 | 153 | const cls = classes.get(topic.subject.value); 154 | assert(cls); 155 | toClass(cls, topic, classes); 156 | } 157 | 158 | for (const cls of classes.values()) { 159 | cls.validateClass(); 160 | } 161 | } 162 | 163 | /** 164 | * Produce a mapping of all Classes within the Ontology. The resulting classes 165 | * are empty and only describes their names, comments, and inheritance 166 | * relations. 167 | * 168 | * @param topics a sequence of processed triples describing an Ontology. 169 | * @returns ClassMap Mapping fully qualified ID of each type to a Class. 170 | */ 171 | export function ProcessClasses(topics: readonly TypedTopic[]): ClassMap { 172 | const classes = ForwardDeclareClasses(topics); 173 | BuildClasses(topics, classes); 174 | return classes; 175 | } 176 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/transform/toEnum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {NamedNode, Quad} from 'n3'; 18 | 19 | import {Log} from '../logging/index.js'; 20 | import {shortStr} from '../triples/term_utils.js'; 21 | import {HasEnumType, TypedTopic} from '../triples/wellKnown.js'; 22 | import {ClassMap} from '../ts/class.js'; 23 | import {EnumValue} from '../ts/enum.js'; 24 | import {assertIs} from '../util/assert.js'; 25 | 26 | /** 27 | * Annotates classes with any Enum values they blong to. 28 | * 29 | * @param topics a sequence of processed triples describing an Ontology. 30 | * @param classes return value of `ProcessClasses`. 31 | */ 32 | export function ProcessEnums(topics: readonly TypedTopic[], classes: ClassMap) { 33 | // Process Enums 34 | for (const topic of topics) { 35 | if (!HasEnumType(topic.types)) continue; 36 | 37 | // Everything Here should be an enum. 38 | assertIs(topic.subject, (s): s is NamedNode => s.termType === 'NamedNode'); 39 | const enumValue = new EnumValue(topic.subject, topic.types, classes); 40 | 41 | const skipped: Quad[] = []; 42 | for (const v of topic.quads) { 43 | if (!enumValue.add(v)) skipped.push(v); 44 | } 45 | 46 | if (skipped.length > 0) { 47 | Log( 48 | `For Enum Item ${shortStr(topic.subject)}, did not process:\n\t${skipped 49 | .map(q => `(${shortStr(q.predicate)}, ${shortStr(q.object)})`) 50 | .join('\n\t')}`, 51 | ); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/transform/toProperty.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {NamedNode, Quad} from 'n3'; 17 | import {shortStr} from '../index.js'; 18 | import {Log} from '../logging/index.js'; 19 | 20 | import {IsPropertyType, TypedTopic} from '../triples/wellKnown.js'; 21 | import {ClassMap} from '../ts/class.js'; 22 | import {PropertyType} from '../ts/property.js'; 23 | import {assertIs} from '../util/assert.js'; 24 | 25 | /** 26 | * Annotates classes with any Property values they blong to. 27 | * 28 | * @param topics a sequence of processed triples describing an Ontology. 29 | * @param classes return value of `ProcessClasses`. 30 | */ 31 | export function ProcessProperties( 32 | topics: readonly TypedTopic[], 33 | classes: ClassMap, 34 | ) { 35 | for (const topic of topics) { 36 | // Skip Topics that have no 'Property' Type. 37 | if (!topic.types.some(IsPropertyType)) continue; 38 | 39 | const rest: Quad[] = []; 40 | assertIs(topic.subject, (s): s is NamedNode => s.termType === 'NamedNode'); 41 | const property = new PropertyType(topic.subject); 42 | for (const value of topic.quads) { 43 | const added = property.add(value, classes); 44 | if (!added) { 45 | rest.push(value); 46 | } 47 | } 48 | // Go over RangeIncludes or DomainIncludes: 49 | if (rest.length > 0) { 50 | Log( 51 | `Still unadded for property: ${shortStr(topic.subject)}:\n\t${rest 52 | .map(q => `(${shortStr(q.predicate)} ${shortStr(q.object)})`) 53 | .join('\n\t')}`, 54 | ); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/transform/transform.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import ts from 'typescript'; 17 | const { 18 | createPrinter, 19 | createSourceFile, 20 | EmitHint, 21 | NewLineKind, 22 | ScriptKind, 23 | ScriptTarget, 24 | } = ts; 25 | 26 | import {asTopicArray} from '../triples/operators.js'; 27 | import {Sort} from '../ts/class.js'; 28 | import {Context} from '../ts/context.js'; 29 | 30 | import {ProcessClasses} from './toClass.js'; 31 | import {ProcessEnums} from './toEnum.js'; 32 | import {ProcessProperties} from './toProperty.js'; 33 | import {HelperTypes} from '../ts/helper_types.js'; 34 | 35 | import {Store} from 'n3'; 36 | 37 | /** 38 | * Writes TypeScript declarations for all Classes, Typedefs, and Enums 39 | * representing the ontology passed in the 'triples' parameter. 40 | * 41 | * @param triples Observable emitting all Triples found in an ontology. 42 | * @param includeDeprecated True if classes and properties marked with 43 | * 'supersededBy' should still be included (as 'deprecated') in the final 44 | * TypeScript output. 45 | * @param write Callback function to write a portion of the file. Will be called 46 | * sequentially on separate chunks within a file. 47 | * 48 | * @returns Promise indicating completion. 49 | */ 50 | export async function WriteDeclarations( 51 | graph: Store, 52 | includeDeprecated: boolean, 53 | context: Context, 54 | write: (content: string) => Promise | void, 55 | ) { 56 | const topics = asTopicArray(graph); 57 | 58 | const classes = ProcessClasses(topics); 59 | ProcessProperties(topics, classes); 60 | ProcessEnums(topics, classes); 61 | const sorted = Array.from(classes.values()).sort(Sort); 62 | 63 | const properties = { 64 | hasRole: !!( 65 | classes.get('http://schema.org/Role') || 66 | classes.get('https://schema.org/Role') 67 | ), 68 | skipDeprecatedProperties: !includeDeprecated, 69 | }; 70 | 71 | const source = createSourceFile( 72 | 'result.ts', 73 | '', 74 | ScriptTarget.ES2015, 75 | /*setParentNodes=*/ false, 76 | ScriptKind.TS, 77 | ); 78 | const printer = createPrinter({newLine: NewLineKind.LineFeed}); 79 | 80 | for (const helperType of HelperTypes(context, properties)) { 81 | await write(printer.printNode(EmitHint.Unspecified, helperType, source)); 82 | await write('\n'); 83 | } 84 | await write('\n'); 85 | 86 | for (const cls of sorted) { 87 | if (cls.deprecated && !includeDeprecated) continue; 88 | 89 | for (const node of cls.toNode(context, properties)) { 90 | const result = printer.printNode(EmitHint.Unspecified, node, source); 91 | await write(result); 92 | await write('\n'); 93 | } 94 | await write('\n'); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/triples/operators.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Store} from 'n3'; 18 | import {GetTypes, IsType} from './wellKnown.js'; 19 | import type {TypedTopic} from './wellKnown.js'; 20 | 21 | export function asTopicArray(store: Store): TypedTopic[] { 22 | return store 23 | .getSubjects(null, null, null) 24 | .map(subject => ({ 25 | subject, 26 | quads: store.getQuads(subject, null, null, null), 27 | })) 28 | .map(topic => ({ 29 | subject: topic.subject, 30 | quads: topic.quads.filter(value => !IsType(value.predicate)), 31 | types: GetTypes(topic.quads), 32 | })); 33 | } 34 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/triples/reader.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import https from 'https'; 17 | import fs from 'fs/promises'; 18 | 19 | import {Log} from '../logging/index.js'; 20 | 21 | import {Parser, Store} from 'n3'; 22 | import type {Quad} from 'n3'; 23 | 24 | function asQuads(data: string): Quad[] { 25 | return new Parser({}).parse(data); 26 | } 27 | 28 | /** 29 | * Loads schema all Triples from a given Schema file and version. 30 | */ 31 | export async function load(url: string): Promise { 32 | const quads = await handleUrl(url); 33 | return process(quads); 34 | } 35 | 36 | /** 37 | * does the same as load(), but for a local file 38 | */ 39 | export async function loadFile(path: string): Promise { 40 | const quads = await handleFile(path); 41 | return process(quads); 42 | } 43 | 44 | async function handleFile(path: string): Promise { 45 | const fileStr = await fs.readFile(path, {encoding: 'utf8'}); 46 | return asQuads(fileStr); 47 | } 48 | 49 | function handleUrl(url: string): Promise { 50 | return new Promise((resolve, reject) => { 51 | https 52 | .get(url, response => { 53 | Log(`Got Response ${response.statusCode}: ${response.statusMessage}.`); 54 | if (response.statusCode !== 200) { 55 | const location = 56 | response.headers['location'] || 57 | response.headers['content-location']; 58 | 59 | if (location) { 60 | Log(`Handling redirect to ${location}...`); 61 | resolve(handleUrl(location)); 62 | return; 63 | } 64 | 65 | reject( 66 | new Error( 67 | `Got Errored Response ${response.statusCode}: ${response.statusMessage}.`, 68 | ), 69 | ); 70 | return; 71 | } 72 | 73 | const data: string[] = []; 74 | 75 | response.on('data', (chunkB: Buffer) => { 76 | const chunk = chunkB.toString('utf-8'); 77 | data.push(chunk); 78 | }); 79 | 80 | response.on('end', () => { 81 | try { 82 | resolve(asQuads(data.join(''))); 83 | } catch (error) { 84 | Log(`Caught Error on end: ${error as Error}`); 85 | reject(error as Error); 86 | } 87 | }); 88 | 89 | response.on('error', error => { 90 | Log(`Saw error: ${error}`); 91 | reject(error); 92 | }); 93 | }) 94 | .on('error', reject); 95 | }); 96 | } 97 | 98 | export function process(quads: Quad[]): Store { 99 | const filtered = quads.filter(quad => { 100 | if ( 101 | quad.subject.termType === 'NamedNode' && 102 | quad.subject.value.includes('file:///') 103 | ) { 104 | // Inexplicably, local files end up in the public schema for 105 | // certain layer overlays. 106 | return false; 107 | } 108 | 109 | return true; 110 | }); 111 | return new Store(filtered); 112 | } 113 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/triples/term_utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import type {NamedNode, Term} from 'n3'; 18 | 19 | export function nameFromContext( 20 | term: NamedNode, 21 | context: string, 22 | ): string | null { 23 | if (term.id.startsWith(context)) { 24 | return cleanName(term.id.replace(new RegExp(`^${context}`), '')); 25 | } 26 | 27 | if (context.startsWith('https:')) { 28 | return nameFromContext(term, context.replace(/^https:/, 'http:')); 29 | } 30 | 31 | return null; 32 | } 33 | function cleanName(n: string | null): string | null { 34 | if (!n) return n; 35 | return n.replace(/^[#/]/, ''); 36 | } 37 | 38 | export function namedPortionOrEmpty(term: NamedNode): string { 39 | const url = new URL(term.id); 40 | if (url.hash.startsWith('#')) return url.hash.replace(/^#/, ''); 41 | const path = url.pathname.split('/'); 42 | return path[path.length - 1]; 43 | } 44 | 45 | export function namedPortion(term: NamedNode): string { 46 | const name = namedPortionOrEmpty(term); 47 | 48 | if (!name) { 49 | throw new Error( 50 | `Expected ${term.id} to have a short name (final path or hash), but found none.`, 51 | ); 52 | } 53 | return name; 54 | } 55 | 56 | export function shortStr(term: Term) { 57 | if (term.termType === 'NamedNode') { 58 | return namedPortionOrEmpty(term) || term.value; 59 | } 60 | return term.value; 61 | } 62 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/action_constraints.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import ts, {factory, ModifierFlags, SyntaxKind} from 'typescript'; 18 | import {arrayOf} from './util/arrayof.js'; 19 | import {withComments} from './util/comments.js'; 20 | 21 | const ActionBaseName = 'ActionBase'; 22 | const InputActionConstraintsName = 'InputActionConstraints'; 23 | const OutputActionConstraintsName = 'OutputActionConstraints'; 24 | 25 | function createIOActionConstraints( 26 | suffix: 'input' | 'output', 27 | ): ts.TypeAliasDeclaration { 28 | const name = 29 | suffix === 'input' 30 | ? InputActionConstraintsName 31 | : OutputActionConstraintsName; 32 | return factory.createTypeAliasDeclaration( 33 | undefined, 34 | name, 35 | arrayOf( 36 | factory.createTypeParameterDeclaration( 37 | [], 38 | 'T', 39 | factory.createTypeReferenceNode(ActionBaseName), 40 | ), 41 | ), 42 | factory.createTypeReferenceNode('Partial', [ 43 | factory.createMappedTypeNode( 44 | undefined, 45 | factory.createTypeParameterDeclaration( 46 | undefined, 47 | 'K', 48 | factory.createTypeReferenceNode('Exclude', [ 49 | factory.createTypeOperatorNode( 50 | SyntaxKind.KeyOfKeyword, 51 | factory.createTypeReferenceNode('T'), 52 | ), 53 | factory.createTemplateLiteralType(factory.createTemplateHead('@'), [ 54 | factory.createTemplateLiteralTypeSpan( 55 | factory.createKeywordTypeNode(SyntaxKind.StringKeyword), 56 | factory.createTemplateTail(''), 57 | ), 58 | ]), 59 | ]), 60 | ), 61 | factory.createTemplateLiteralType(factory.createTemplateHead(''), [ 62 | factory.createTemplateLiteralTypeSpan( 63 | factory.createIntersectionTypeNode([ 64 | factory.createKeywordTypeNode(SyntaxKind.StringKeyword), 65 | factory.createTypeReferenceNode('K'), 66 | ]), 67 | factory.createTemplateTail(`-${suffix}`), 68 | ), 69 | ]), 70 | undefined, 71 | factory.createUnionTypeNode([ 72 | factory.createTypeReferenceNode('PropertyValueSpecification'), 73 | factory.createKeywordTypeNode(SyntaxKind.StringKeyword), 74 | ]), 75 | undefined, 76 | ), 77 | ]), 78 | ); 79 | } 80 | 81 | export const InputActionConstraintsType = createIOActionConstraints('input'); 82 | export const OutputActionConstraintsType = createIOActionConstraints('output'); 83 | export const WithActionConstraintsType = withComments( 84 | 'Provides input and output action constraints for an action.', 85 | factory.createTypeAliasDeclaration( 86 | factory.createModifiersFromModifierFlags(ModifierFlags.Export), 87 | 'WithActionConstraints', 88 | arrayOf( 89 | factory.createTypeParameterDeclaration( 90 | [], 91 | 'T', 92 | factory.createTypeReferenceNode(ActionBaseName), 93 | ), 94 | ), 95 | factory.createIntersectionTypeNode([ 96 | factory.createTypeReferenceNode('T'), 97 | factory.createTypeReferenceNode(InputActionConstraintsName, [ 98 | factory.createTypeReferenceNode('T'), 99 | ]), 100 | factory.createTypeReferenceNode(OutputActionConstraintsName, [ 101 | factory.createTypeReferenceNode('T'), 102 | ]), 103 | ]), 104 | ), 105 | ); 106 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/context.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import ts from 'typescript'; 18 | import type {PropertySignature} from 'typescript'; 19 | const {factory} = ts; 20 | 21 | import {NamedNode} from 'n3'; 22 | import {nameFromContext} from '../triples/term_utils.js'; 23 | 24 | export class Context { 25 | private readonly context: Array = []; 26 | 27 | setUrlContext(ctx: string) { 28 | if (this.context.length > 0) { 29 | throw new Error( 30 | 'Attempting to set a default URL context, ' + 31 | 'but other named contexts exist already.', 32 | ); 33 | } 34 | this.context.push(['', ctx]); 35 | } 36 | addNamedContext(name: string, url: string) { 37 | this.context.push([name, url]); 38 | } 39 | validate() { 40 | if (this.context.length === 0) throw new Error('Invalid empty context.'); 41 | if (this.context.length === 1) return; // One context is always right. 42 | 43 | // Make sure no key is duplicated. 44 | const seen: Set = new Set(); 45 | for (const [name] of this.context) { 46 | if (seen.has(name)) { 47 | throw new Error(`Named context ${name} found twice in context.`); 48 | } 49 | if (name === '') { 50 | throw new Error( 51 | 'Context with multiple named contexts includes unnamed URL.', 52 | ); 53 | } 54 | seen.add(name); 55 | } 56 | } 57 | 58 | getScopedName(node: NamedNode): string { 59 | for (const [ctxName, url] of this.context) { 60 | const name = nameFromContext(node, url); 61 | if (name !== null) { 62 | // Valid possibilities: 63 | // - "schema:Foo" when name == schema && node.name == Foo. 64 | // - "schema:" when name == schema && node.name is undefined. 65 | // - "Foo" when name is empty and node.name is Foo. 66 | // 67 | // Don't allow "" when name is empty and node.name is undefined. 68 | return ctxName === '' ? name || node.id : `${ctxName}:${name}`; 69 | } 70 | } 71 | return node.id; 72 | } 73 | 74 | private typeNode() { 75 | // Either: 76 | // "@context": "https://schema.org" or similar: 77 | if (this.context.length === 1 && this.context[0][0] === '') { 78 | return factory.createLiteralTypeNode( 79 | factory.createStringLiteral(this.context[0][1]), 80 | ); 81 | } 82 | 83 | // or "@context" is a literal object type of key-values of URLs: 84 | return factory.createTypeLiteralNode( 85 | /*members=*/ this.context.map(([name, url]) => 86 | factory.createPropertySignature( 87 | /*modifiers=*/ [], 88 | factory.createStringLiteral(name), 89 | /*questionToken=*/ undefined, 90 | factory.createLiteralTypeNode(factory.createStringLiteral(url)), 91 | ), 92 | ), 93 | ); 94 | } 95 | 96 | /** Creates the full property signature for "@context" given the configured context. */ 97 | contextProperty(): PropertySignature { 98 | return factory.createPropertySignature( 99 | /*modifiers=*/ [], 100 | factory.createStringLiteral('@context'), 101 | /*questionToken=*/ undefined, 102 | this.typeNode(), 103 | ); 104 | } 105 | 106 | static Parse(contextSpec: string): Context { 107 | const keyVals = contextSpec 108 | .split(',') 109 | .map(s => s.trim()) 110 | .filter(s => !!s); 111 | const context = new Context(); 112 | 113 | if (keyVals.length === 1) { 114 | context.setUrlContext(keyVals[0]); 115 | } else { 116 | for (const keyVal of keyVals) { 117 | const match = /^([^:]+):((http|https):.+)$/g.exec(keyVal); 118 | if (!match || match[1] === undefined || match[2] === undefined) { 119 | throw new Error(`Unknown value ${keyVal} in --context flag.`); 120 | } 121 | context.addNamedContext(match[1], match[2]); 122 | } 123 | } 124 | 125 | context.validate(); 126 | return context; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import ts from 'typescript'; 17 | import type {TypeNode} from 'typescript'; 18 | const {factory} = ts; 19 | 20 | import {Log} from '../logging/index.js'; 21 | 22 | import {GetComment, IsClassType, IsDataType} from '../triples/wellKnown.js'; 23 | 24 | import {ClassMap} from './class.js'; 25 | import {Context} from './context.js'; 26 | 27 | import type {NamedNode, Quad} from 'n3'; 28 | 29 | /** 30 | * Corresponds to a value that belongs to an Enumeration. 31 | */ 32 | export class EnumValue { 33 | readonly INSTANCE = 'EnumValue'; 34 | 35 | private comment?: string; 36 | constructor( 37 | readonly value: NamedNode, 38 | types: readonly NamedNode[], 39 | map: ClassMap, 40 | ) { 41 | for (const type of types) { 42 | // If a Subject has a "Type", then it either means: 43 | // 1- Type is Class - This topic represents an object that can be 44 | // represented as a class (usually, a node/object). 45 | // 2- Type is DataType - This topic represents an object that can 46 | // represented as a raw value. 47 | // 3- Type is Neither - This topic's IRI can be used in the place of that 48 | // type to describe its value. 49 | // 50 | // For example, 51 | // - Thing is a Class only. 52 | // - Text is a Class and a DataType. 53 | // - DataType is a Class. 54 | // - Wednesday is a DayOfWeek only. 55 | // 56 | // In Schema.org 3.4, some enumerations were both a Class and an Enum. 57 | // 58 | // For example, SurgicalProcedure was both an enum value for 59 | // MedicalProcedureType and a class that can be described in its own 60 | // right. It had type Class and MedicalProcedureType. 61 | // 62 | // For those cases, we make sure: 63 | // (a) We add an EnumValue for all types that are not Class/DataType. 64 | // (b) An EnumValue being a Class/DataType should not disqualify it from 65 | // being an enum value for some other type (if it has one). 66 | if (IsClassType(type) || IsDataType(type)) continue; 67 | 68 | const enumObject = map.get(type.id); 69 | if (!enumObject) { 70 | throw new Error(`Couldn't find ${type.id} in classes.`); 71 | } 72 | enumObject.addEnum(this); 73 | } 74 | } 75 | 76 | add(value: Quad) { 77 | const comment = GetComment(value); 78 | if (comment) { 79 | if (this.comment) { 80 | Log( 81 | `Duplicate comments provided on ${this.value.id} enum but one already exists. It will be overwritten.`, 82 | ); 83 | } 84 | this.comment = comment.comment; 85 | return true; 86 | } 87 | 88 | return false; 89 | } 90 | 91 | toTypeLiteral(context: Context): TypeNode[] { 92 | const types = [this.value.id]; 93 | 94 | if (this.value.id.startsWith('http:')) { 95 | types.push(this.value.id.replace(/^http:/, 'https:')); 96 | } 97 | 98 | const scoped = context.getScopedName(this.value); 99 | if (scoped !== this.value.id) { 100 | types.push(scoped); 101 | } 102 | 103 | return types.map(t => 104 | factory.createLiteralTypeNode(factory.createStringLiteral(t)), 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/helper_types.ts: -------------------------------------------------------------------------------- 1 | import ts from 'typescript'; 2 | import type {TypeNode} from 'typescript'; 3 | const {factory, SyntaxKind, ModifierFlags} = ts; 4 | 5 | import { 6 | WithActionConstraintsType, 7 | InputActionConstraintsType, 8 | OutputActionConstraintsType, 9 | } from './action_constraints.js'; 10 | import {Context} from './context.js'; 11 | 12 | import {arrayOf} from './util/arrayof.js'; 13 | import {withComments} from './util/comments.js'; 14 | import {typeUnion} from './util/union.js'; 15 | 16 | function IdPropertyNode() { 17 | return withComments( 18 | 'IRI identifying the canonical address of this object.', 19 | factory.createPropertySignature( 20 | /* modifiers= */ [], 21 | factory.createStringLiteral('@id'), 22 | /* questionToken= */ undefined, 23 | /* typeNode= */ 24 | factory.createTypeReferenceNode('string', /*typeArguments=*/ []), 25 | ), 26 | ); 27 | } 28 | 29 | function WithContextType(context: Context) { 30 | // export type WithContext = T & { "@context": TYPE_NODE } 31 | return withComments( 32 | 'Used at the top-level node to indicate the context for the JSON-LD ' + 33 | 'objects used. The context provided in this type is compatible ' + 34 | 'with the keys and URLs in the rest of this generated file.', 35 | factory.createTypeAliasDeclaration( 36 | factory.createModifiersFromModifierFlags(ModifierFlags.Export), 37 | 'WithContext', 38 | [ 39 | factory.createTypeParameterDeclaration( 40 | /*modifiers=*/ [], 41 | 'T' /*constraint=*/, 42 | factory.createTypeReferenceNode( 43 | 'Thing', 44 | /*typeArguments=*/ undefined, 45 | ), 46 | ), 47 | ], 48 | factory.createIntersectionTypeNode([ 49 | factory.createTypeReferenceNode('T', /*typeArguments=*/ undefined), 50 | factory.createTypeLiteralNode([context.contextProperty()]), 51 | ]), 52 | ), 53 | ); 54 | } 55 | 56 | function GraphType(context: Context) { 57 | return withComments( 58 | '', 59 | factory.createInterfaceDeclaration( 60 | factory.createModifiersFromModifierFlags(ModifierFlags.Export), 61 | GraphTypeName, 62 | /*typeParameters=*/ undefined, 63 | /*heritageClauses=*/ undefined, 64 | [ 65 | context.contextProperty(), 66 | factory.createPropertySignature( 67 | /*modifiers=*/ [], 68 | factory.createStringLiteral('@graph'), 69 | /*questionToken=*/ undefined, 70 | factory.createTypeOperatorNode( 71 | SyntaxKind.ReadonlyKeyword, 72 | factory.createArrayTypeNode( 73 | factory.createTypeReferenceNode( 74 | 'Thing', 75 | /*typeArguments=*/ undefined, 76 | ), 77 | ), 78 | ), 79 | ), 80 | ], 81 | ), 82 | ); 83 | } 84 | 85 | const SchemaValueName = 'SchemaValue'; 86 | export const IdReferenceName = 'IdReference'; 87 | export const GraphTypeName = 'Graph'; 88 | 89 | export function SchemaValueReference( 90 | {hasRole}: {hasRole: boolean}, 91 | makeScalarType: () => TypeNode, 92 | propertyName: string, 93 | ) { 94 | return factory.createTypeReferenceNode( 95 | SchemaValueName, 96 | /* typeArguments = */ arrayOf( 97 | makeScalarType(), 98 | hasRole && 99 | factory.createLiteralTypeNode( 100 | factory.createStringLiteral(propertyName), 101 | ), 102 | ), 103 | ); 104 | } 105 | 106 | export function HelperTypes(context: Context, {hasRole}: {hasRole: boolean}) { 107 | return [ 108 | WithContextType(context), 109 | GraphType(context), 110 | factory.createTypeAliasDeclaration( 111 | /*modifiers=*/ [], 112 | SchemaValueName, 113 | arrayOf( 114 | factory.createTypeParameterDeclaration(/*modifiers=*/ [], 'T'), 115 | hasRole && 116 | factory.createTypeParameterDeclaration( 117 | /*modifiers=*/ [], 118 | 'TProperty', 119 | /*constraint=*/ factory.createTypeReferenceNode('string'), 120 | ), 121 | ), 122 | factory.createUnionTypeNode( 123 | arrayOf( 124 | factory.createTypeReferenceNode('T', /*typeArguments=*/ []), 125 | hasRole && 126 | factory.createTypeReferenceNode('Role', [ 127 | /*TContent=*/ factory.createTypeReferenceNode('T'), 128 | /*TProperty=*/ factory.createTypeReferenceNode('TProperty'), 129 | ]), 130 | factory.createTypeOperatorNode( 131 | SyntaxKind.ReadonlyKeyword, 132 | factory.createArrayTypeNode( 133 | typeUnion( 134 | factory.createTypeReferenceNode('T', /*typeArguments=*/ []), 135 | hasRole && 136 | factory.createTypeReferenceNode('Role', [ 137 | /*TContent=*/ factory.createTypeReferenceNode('T'), 138 | /*TProperty=*/ factory.createTypeReferenceNode('TProperty'), 139 | ]), 140 | ), 141 | ), 142 | ), 143 | ), 144 | ), 145 | ), 146 | factory.createTypeAliasDeclaration( 147 | /*modifiers=*/ [], 148 | IdReferenceName, 149 | /*typeParameters=*/ [], 150 | factory.createTypeLiteralNode([IdPropertyNode()]), 151 | ), 152 | InputActionConstraintsType, 153 | OutputActionConstraintsType, 154 | WithActionConstraintsType, 155 | ]; 156 | } 157 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/property.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import ts from 'typescript'; 18 | import type {PropertySignature} from 'typescript'; 19 | const {factory, SyntaxKind} = ts; 20 | 21 | import {Log} from '../logging/index.js'; 22 | import { 23 | GetComment, 24 | IsDomainIncludes, 25 | IsRangeIncludes, 26 | IsSupersededBy, 27 | IsTypeName, 28 | } from '../triples/wellKnown.js'; 29 | 30 | import type {Class, ClassMap} from './class.js'; 31 | import {Context} from './context.js'; 32 | import {appendParagraph, withComments} from './util/comments.js'; 33 | import {IdReferenceName, SchemaValueReference} from './helper_types.js'; 34 | import {typeUnion} from './util/union.js'; 35 | 36 | import type {NamedNode, Quad} from 'n3'; 37 | import {assertIs} from '../util/assert.js'; 38 | 39 | /** 40 | * A "class" of properties, not associated with any particuar object. 41 | */ 42 | export class PropertyType { 43 | private readonly types: Class[] = []; 44 | private _comment?: string; 45 | private readonly _supersededBy: NamedNode[] = []; 46 | 47 | constructor(private readonly subject: NamedNode) {} 48 | 49 | get comment() { 50 | if (!this.deprecated) return this._comment; 51 | const deprecated = `@deprecated Consider using ${this._supersededBy 52 | .map(o => o.id) 53 | .join(' or ')} instead.`; 54 | 55 | return appendParagraph(this._comment, deprecated); 56 | } 57 | 58 | get deprecated() { 59 | return this._supersededBy.length > 0; 60 | } 61 | 62 | add(value: Quad, classes: ClassMap): boolean { 63 | const c = GetComment(value); 64 | if (c) { 65 | if (this._comment) { 66 | Log( 67 | `Duplicate comments provided on property ${this.subject.id}. It will be overwritten.`, 68 | ); 69 | } 70 | this._comment = c.comment; 71 | return true; 72 | } 73 | 74 | if (IsRangeIncludes(value.predicate)) { 75 | if (!IsTypeName(value.object)) { 76 | throw new Error( 77 | `Type expected to be a UrlNode always. When adding ${JSON.stringify( 78 | value.toJSON(), 79 | undefined, 80 | 2, 81 | )}.`, 82 | ); 83 | } 84 | const cls = classes.get(value.object.id); 85 | if (!cls) { 86 | throw new Error( 87 | `Could not find class for ${value.object.id} [only foud: ${Array.from( 88 | classes.keys(), 89 | ).join(', ')}]`, 90 | ); 91 | } 92 | this.types.push(cls); 93 | return true; 94 | } 95 | 96 | if (IsDomainIncludes(value.predicate)) { 97 | const cls = classes.get(value.object.id); 98 | if (!cls) { 99 | throw new Error( 100 | `Could not find class for ${ 101 | value.object.id 102 | }. [only foud: ${Array.from(classes.keys()).join(', ')}]`, 103 | ); 104 | } 105 | cls.addProp(new Property(this.subject, this)); 106 | return true; 107 | } 108 | 109 | if (IsSupersededBy(value.predicate)) { 110 | assertIs(value.object, (o): o is NamedNode => o.termType === 'NamedNode'); 111 | this._supersededBy.push(value.object); 112 | return true; 113 | } 114 | 115 | return false; 116 | } 117 | 118 | scalarTypeNode() { 119 | const typeNames = this.types.map(cls => cls.className()).sort(); 120 | if (this.types.some(cls => cls.isNodeType())) { 121 | typeNames.push(IdReferenceName); 122 | } 123 | 124 | const typeNodes = typeNames.map(type => 125 | factory.createTypeReferenceNode(type, /*typeArguments=*/ []), 126 | ); 127 | 128 | return typeUnion(...typeNodes); 129 | } 130 | } 131 | 132 | /** 133 | * A Property on a particular object. 134 | */ 135 | export class Property { 136 | constructor( 137 | readonly key: NamedNode, 138 | private readonly type: PropertyType, 139 | ) {} 140 | 141 | get deprecated() { 142 | return this.type.deprecated; 143 | } 144 | 145 | private typeNode(context: Context, properties: {hasRole: boolean}) { 146 | return SchemaValueReference( 147 | properties, 148 | () => this.type.scalarTypeNode(), 149 | context.getScopedName(this.key), 150 | ); 151 | } 152 | 153 | toNode(context: Context, properties: {hasRole: boolean}): PropertySignature { 154 | return withComments( 155 | this.type.comment, 156 | factory.createPropertySignature( 157 | /* modifiers= */ [], 158 | factory.createStringLiteral(context.getScopedName(this.key)), 159 | factory.createToken(SyntaxKind.QuestionToken), 160 | /*typeNode=*/ this.typeNode(context, properties), 161 | ), 162 | ); 163 | } 164 | } 165 | 166 | export class TypeProperty { 167 | constructor(private readonly className: NamedNode) {} 168 | 169 | toNode(context: Context) { 170 | return factory.createPropertySignature( 171 | /* modifiers= */ [], 172 | factory.createStringLiteral('@type'), 173 | /* questionToken= */ undefined, 174 | /* typeNode= */ 175 | factory.createTypeReferenceNode( 176 | `"${context.getScopedName(this.className)}"`, 177 | /*typeArguments=*/ undefined, 178 | ), 179 | ); 180 | } 181 | 182 | readonly deprecated = false; 183 | } 184 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/util/arrayof.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export function arrayOf( 18 | ...args: Array 19 | ): T[] { 20 | return args.filter((elem): elem is T => !!elem); 21 | } 22 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/util/names.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import type {NamedNode} from 'n3'; 18 | import {namedPortion} from '../../triples/term_utils.js'; 19 | 20 | function decodeOr(component: string) { 21 | try { 22 | return decodeURIComponent(component); 23 | } catch { 24 | return component; 25 | } 26 | } 27 | 28 | export function toClassName(subject: NamedNode): string { 29 | let sanitizedName = decodeOr(namedPortion(subject)).replace( 30 | /[^A-Za-z0-9_]/g, 31 | '_', 32 | ); 33 | 34 | // No leading numbers. 35 | if (/^[0-9]/g.test(sanitizedName)) { 36 | sanitizedName = `_${sanitizedName}`; 37 | } 38 | 39 | return sanitizedName; 40 | } 41 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/ts/util/union.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import ts from 'typescript'; 18 | import type {TypeNode} from 'typescript'; 19 | const {factory, SyntaxKind} = ts; 20 | 21 | export function typeUnion( 22 | ...args: Array 23 | ): TypeNode { 24 | const types = args.filter((elem): elem is TypeNode => !!elem); 25 | 26 | switch (types.length) { 27 | case 0: 28 | return factory.createKeywordTypeNode(SyntaxKind.NeverKeyword); 29 | case 1: 30 | return types[0]; 31 | default: 32 | return factory.createUnionTypeNode(types); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/src", 5 | "rootDir": ".", 6 | "skipLibCheck": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/src/util/assert.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {ok} from 'assert'; 18 | 19 | export function assert( 20 | item: T | null | undefined, 21 | message?: string | Error, 22 | ): asserts item is T { 23 | ok(item, message); 24 | } 25 | 26 | export function assertIs( 27 | item: T, 28 | assertion: (i: T) => i is U, 29 | message?: string, 30 | ): asserts item is U { 31 | ok(assertion(item), message); 32 | } 33 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/category_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual, actualLogs} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | "issue-743" . 35 | "Distillery" . 36 | "A distillery." . 37 | . 38 | . 39 | `, 40 | [ 41 | '--ontology', 42 | `https://fake.com/${basename(import.meta.url)}.nt`, 43 | '--verbose', 44 | ], 45 | ); 46 | 47 | expect(actual).toMatchInlineSnapshot(` 48 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 49 | export type WithContext = T & { 50 | "@context": "https://schema.org"; 51 | }; 52 | export interface Graph { 53 | "@context": "https://schema.org"; 54 | "@graph": readonly Thing[]; 55 | } 56 | type SchemaValue = T | readonly T[]; 57 | type IdReference = { 58 | /** IRI identifying the canonical address of this object. */ 59 | "@id": string; 60 | }; 61 | type InputActionConstraints = Partial<{ 62 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 63 | }>; 64 | type OutputActionConstraints = Partial<{ 65 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 66 | }>; 67 | /** Provides input and output action constraints for an action. */ 68 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 69 | 70 | export type Text = string; 71 | 72 | interface DistilleryLeaf extends ThingBase { 73 | "@type": "Distillery"; 74 | } 75 | /** A distillery. */ 76 | export type Distillery = DistilleryLeaf; 77 | 78 | interface ThingBase extends Partial { 79 | "name"?: SchemaValue; 80 | } 81 | interface ThingLeaf extends ThingBase { 82 | "@type": "Thing"; 83 | } 84 | export type Thing = ThingLeaf | Distillery; 85 | 86 | " 87 | `); 88 | expect(actualLogs).toMatchInlineSnapshot(` 89 | "Loading Ontology from URL: https://fake.com/category_test.ts.nt 90 | Got Response 200: Ok. 91 | Class Distillery: Did not add [(source 743),(category issue-743),(label Distillery)] 92 | " 93 | `); 94 | }); 95 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/data_type_union_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | "The basic data types such as Integers, Strings, etc." . 39 | . 40 | . 41 | `, 42 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 43 | ); 44 | 45 | expect(actual).toMatchInlineSnapshot(` 46 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 47 | export type WithContext = T & { 48 | "@context": "https://schema.org"; 49 | }; 50 | export interface Graph { 51 | "@context": "https://schema.org"; 52 | "@graph": readonly Thing[]; 53 | } 54 | type SchemaValue = T | readonly T[]; 55 | type IdReference = { 56 | /** IRI identifying the canonical address of this object. */ 57 | "@id": string; 58 | }; 59 | type InputActionConstraints = Partial<{ 60 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 61 | }>; 62 | type OutputActionConstraints = Partial<{ 63 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 64 | }>; 65 | /** Provides input and output action constraints for an action. */ 66 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 67 | 68 | export type Number = number | \`\${number}\`; 69 | 70 | export type Text = string; 71 | 72 | /** The basic data types such as Integers, Strings, etc. */ 73 | export type DataType = Number | Text; 74 | 75 | interface ThingBase extends Partial { 76 | "age"?: SchemaValue; 77 | "name"?: SchemaValue; 78 | } 79 | interface ThingLeaf extends ThingBase { 80 | "@type": "Thing"; 81 | } 82 | export type Thing = ThingLeaf; 83 | 84 | " 85 | `); 86 | }); 87 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/default_ontology_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual, actualLogs} = await inlineCli( 26 | ` 27 | . 28 | `, 29 | ['--verbose'], 30 | ); 31 | 32 | expect(actual).toMatchInlineSnapshot(` 33 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 34 | export type WithContext = T & { 35 | "@context": "https://schema.org"; 36 | }; 37 | export interface Graph { 38 | "@context": "https://schema.org"; 39 | "@graph": readonly Thing[]; 40 | } 41 | type SchemaValue = T | readonly T[]; 42 | type IdReference = { 43 | /** IRI identifying the canonical address of this object. */ 44 | "@id": string; 45 | }; 46 | type InputActionConstraints = Partial<{ 47 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 48 | }>; 49 | type OutputActionConstraints = Partial<{ 50 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 51 | }>; 52 | /** Provides input and output action constraints for an action. */ 53 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 54 | 55 | interface ThingBase extends Partial { 56 | } 57 | interface ThingLeaf extends ThingBase { 58 | "@type": "Thing"; 59 | } 60 | export type Thing = ThingLeaf; 61 | 62 | " 63 | `); 64 | expect(actualLogs).toMatchInlineSnapshot(` 65 | "Loading Ontology from URL: https://schema.org/version/latest/schemaorg-all-https.nt 66 | Got Response 200: Ok. 67 | " 68 | `); 69 | }); 70 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/duplicate_comments_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual, actualLogs} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | "Simple!" . 32 | "Simple!" . 33 | "Names are great!\\n
Y"@en . 34 | "Things are amazing!\\n\\n

  • Foo
  • Bar
  • Baz, and Bat
    • "@en . 35 | . 36 | . 37 | "Simple!" . 38 | "Complex!" . 39 | . 40 | . 41 | `, 42 | [ 43 | '--ontology', 44 | `https://fake.com/${basename(import.meta.url)}.nt`, 45 | `--verbose`, 46 | ], 47 | ); 48 | 49 | expect(actual).toMatchInlineSnapshot(` 50 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 51 | export type WithContext = T & { 52 | "@context": "https://schema.org"; 53 | }; 54 | export interface Graph { 55 | "@context": "https://schema.org"; 56 | "@graph": readonly Thing[]; 57 | } 58 | type SchemaValue = T | readonly T[]; 59 | type IdReference = { 60 | /** IRI identifying the canonical address of this object. */ 61 | "@id": string; 62 | }; 63 | type InputActionConstraints = Partial<{ 64 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 65 | }>; 66 | type OutputActionConstraints = Partial<{ 67 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 68 | }>; 69 | /** Provides input and output action constraints for an action. */ 70 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 71 | 72 | export type Text = string; 73 | 74 | interface ThingBase extends Partial { 75 | /** 76 | * Names are great! 77 | * {@link X Y} 78 | */ 79 | "name"?: SchemaValue; 80 | } 81 | interface ThingLeaf extends ThingBase { 82 | "@type": "Thing"; 83 | } 84 | /** 85 | * Things are amazing! 86 | * 87 | * - Foo 88 | * - Bar 89 | * - _Baz_, and __Bat__ 90 | */ 91 | export type Thing = "http://schema.org/Gadget" | "https://schema.org/Gadget" | "Gadget" | "http://schema.org/Widget" | "https://schema.org/Widget" | "Widget" | ThingLeaf; 92 | 93 | " 94 | `); 95 | expect(actualLogs).toMatchInlineSnapshot(` 96 | "Loading Ontology from URL: https://fake.com/duplicate_comments_test.ts.nt 97 | Got Response 200: Ok. 98 | Duplicate comments provided on class http://schema.org/Thing. It will be overwritten. 99 | Duplicate comments provided on property http://schema.org/name. It will be overwritten. 100 | Duplicate comments provided on http://schema.org/Gadget enum but one already exists. It will be overwritten. 101 | " 102 | `); 103 | }); 104 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/enum_skipped_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual, actualLogs} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | "A letter!" . 34 | "issue-1156" . 35 | . 36 | "A Thing!" . 37 | `, 38 | [ 39 | '--ontology', 40 | `https://fake.com/${basename(import.meta.url)}.nt`, 41 | `--verbose`, 42 | ], 43 | ); 44 | 45 | expect(actual).toMatchInlineSnapshot(` 46 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 47 | export type WithContext = T & { 48 | "@context": "https://schema.org"; 49 | }; 50 | export interface Graph { 51 | "@context": "https://schema.org"; 52 | "@graph": readonly Thing[]; 53 | } 54 | type SchemaValue = T | readonly T[]; 55 | type IdReference = { 56 | /** IRI identifying the canonical address of this object. */ 57 | "@id": string; 58 | }; 59 | type InputActionConstraints = Partial<{ 60 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 61 | }>; 62 | type OutputActionConstraints = Partial<{ 63 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 64 | }>; 65 | /** Provides input and output action constraints for an action. */ 66 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 67 | 68 | interface ThingBase extends Partial { 69 | } 70 | interface ThingLeaf extends ThingBase { 71 | "@type": "Thing"; 72 | } 73 | /** A Thing! */ 74 | export type Thing = "http://schema.org/a" | "https://schema.org/a" | "a" | "http://schema.org/b" | "https://schema.org/b" | "b" | "http://schema.org/c" | "https://schema.org/c" | "c" | "http://schema.org/d" | "https://schema.org/d" | "d" | "https://schema.org/e" | "e" | "http://google.com/f" | "https://google.com/f" | ThingLeaf; 75 | 76 | " 77 | `); 78 | expect(actualLogs).toMatchInlineSnapshot(` 79 | "Loading Ontology from URL: https://fake.com/enum_skipped_test.ts.nt 80 | Got Response 200: Ok. 81 | For Enum Item c, did not process: 82 | (category, issue-1156) 83 | " 84 | `); 85 | }); 86 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/inheritance_multiple_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | `, 46 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 47 | ); 48 | 49 | expect(actual).toMatchInlineSnapshot(` 50 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 51 | export type WithContext = T & { 52 | "@context": "https://schema.org"; 53 | }; 54 | export interface Graph { 55 | "@context": "https://schema.org"; 56 | "@graph": readonly Thing[]; 57 | } 58 | type SchemaValue = T | readonly T[]; 59 | type IdReference = { 60 | /** IRI identifying the canonical address of this object. */ 61 | "@id": string; 62 | }; 63 | type InputActionConstraints = Partial<{ 64 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 65 | }>; 66 | type OutputActionConstraints = Partial<{ 67 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 68 | }>; 69 | /** Provides input and output action constraints for an action. */ 70 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 71 | 72 | export type Number = number | \`\${number}\`; 73 | 74 | export type Text = string; 75 | 76 | interface PersonLikeBase extends ThingBase { 77 | "height"?: SchemaValue; 78 | } 79 | interface PersonLikeLeaf extends PersonLikeBase { 80 | "@type": "PersonLike"; 81 | } 82 | export type PersonLike = PersonLikeLeaf; 83 | 84 | interface ThingBase extends Partial { 85 | "name"?: SchemaValue; 86 | } 87 | interface ThingLeaf extends ThingBase { 88 | "@type": "Thing"; 89 | } 90 | export type Thing = ThingLeaf | PersonLike | Vehicle; 91 | 92 | interface VehicleBase extends ThingBase { 93 | "doors"?: SchemaValue; 94 | } 95 | interface VehicleLeaf extends VehicleBase { 96 | "@type": "Vehicle"; 97 | } 98 | export type Vehicle = VehicleLeaf; 99 | 100 | " 101 | `); 102 | }); 103 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/inheritance_one_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | `, 41 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 42 | ); 43 | 44 | expect(actual).toMatchInlineSnapshot(` 45 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 46 | export type WithContext = T & { 47 | "@context": "https://schema.org"; 48 | }; 49 | export interface Graph { 50 | "@context": "https://schema.org"; 51 | "@graph": readonly Thing[]; 52 | } 53 | type SchemaValue = T | readonly T[]; 54 | type IdReference = { 55 | /** IRI identifying the canonical address of this object. */ 56 | "@id": string; 57 | }; 58 | type InputActionConstraints = Partial<{ 59 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 60 | }>; 61 | type OutputActionConstraints = Partial<{ 62 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 63 | }>; 64 | /** Provides input and output action constraints for an action. */ 65 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 66 | 67 | export type Number = number | \`\${number}\`; 68 | 69 | export type Text = string; 70 | 71 | interface PersonLikeBase extends ThingBase { 72 | "height"?: SchemaValue; 73 | } 74 | interface PersonLikeLeaf extends PersonLikeBase { 75 | "@type": "PersonLike"; 76 | } 77 | export type PersonLike = PersonLikeLeaf; 78 | 79 | interface ThingBase extends Partial { 80 | "name"?: SchemaValue; 81 | } 82 | interface ThingLeaf extends ThingBase { 83 | "@type": "Thing"; 84 | } 85 | export type Thing = ThingLeaf | PersonLike; 86 | 87 | " 88 | `); 89 | }); 90 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/invalid_schemas_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`invalidSyntax_${basename(import.meta.url)}`, async () => { 25 | const run = inlineCli( 26 | ` 27 | <"INVALID> "X" . 28 | `, 29 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 30 | ); 31 | 32 | await expect(run).rejects.toThrowError('Unexpected'); 33 | }); 34 | 35 | test(`unnamedURLClass_${basename(import.meta.url)}`, async () => { 36 | const run = inlineCli( 37 | ` 38 | . 39 | `, 40 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 41 | ); 42 | 43 | await expect(run).rejects.toThrowError('to have a short name'); 44 | }); 45 | 46 | test(`notMarkedAsClass_cycle_${basename(import.meta.url)}`, async () => { 47 | const run = inlineCli( 48 | ` 49 | . 50 | . 51 | . 52 | "ABC" . 53 | . 54 | "ABC" . 55 | . 56 | . 57 | . 58 | "Data type: Text." . 59 | `, 60 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 61 | ); 62 | 63 | await expect(run).rejects.toThrowError( 64 | 'Thing is not marked as an rdfs:Class', 65 | ); 66 | }); 67 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/must_define_datatype_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | await expect( 26 | inlineCli( 27 | ` 28 | . 29 | . 30 | . 31 | . 32 | `, 33 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 34 | ), 35 | ).rejects.toThrow('Could not find class for http://schema.org/Text'); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/nested_datatype_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | . 46 | . 47 | . 48 | . 49 | . 50 | . 51 | . 52 | . 53 | . 54 | . 55 | `, 56 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 57 | ); 58 | 59 | expect(actual).toMatchInlineSnapshot(` 60 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 61 | export type WithContext = T & { 62 | "@context": "https://schema.org"; 63 | }; 64 | export interface Graph { 65 | "@context": "https://schema.org"; 66 | "@graph": readonly Thing[]; 67 | } 68 | type SchemaValue = T | readonly T[]; 69 | type IdReference = { 70 | /** IRI identifying the canonical address of this object. */ 71 | "@id": string; 72 | }; 73 | type InputActionConstraints = Partial<{ 74 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 75 | }>; 76 | type OutputActionConstraints = Partial<{ 77 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 78 | }>; 79 | /** Provides input and output action constraints for an action. */ 80 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 81 | 82 | export type Text = PronounceableText | URL | string; 83 | 84 | interface ArabicTextBase extends PronounceableTextBase { 85 | "arabicPhoneticText"?: SchemaValue; 86 | } 87 | interface ArabicTextLeaf extends ArabicTextBase { 88 | "@type": "ArabicText"; 89 | } 90 | export type ArabicText = ArabicTextLeaf | string; 91 | 92 | interface EnglishTextLeaf extends PronounceableTextBase { 93 | "@type": "EnglishText"; 94 | } 95 | export type EnglishText = EnglishTextLeaf | string; 96 | 97 | export type FancyURL = string; 98 | 99 | interface PronounceableTextBase extends Partial { 100 | "phoneticText"?: SchemaValue; 101 | } 102 | interface PronounceableTextLeaf extends PronounceableTextBase { 103 | "@type": "PronounceableText"; 104 | } 105 | export type PronounceableText = PronounceableTextLeaf | ArabicText | EnglishText | string; 106 | 107 | interface ThingBase extends Partial { 108 | "name"?: SchemaValue; 109 | "pronunciation"?: SchemaValue; 110 | "website"?: SchemaValue; 111 | } 112 | interface ThingLeaf extends ThingBase { 113 | "@type": "Thing"; 114 | } 115 | export type Thing = ThingLeaf; 116 | 117 | export type URL = FancyURL | string; 118 | 119 | " 120 | `); 121 | }); 122 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/nodeprecated_objects_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | . 46 | . 47 | . 48 | . 49 | . 50 | . 51 | . 52 | "Names are great!\\n Y" . 53 | . 54 | . 55 | . 56 | . 57 | . 58 | . 59 | `, 60 | [ 61 | '--ontology', 62 | `https://fake.com/${basename(import.meta.url)}.nt`, 63 | '--nodeprecated', 64 | ], 65 | ); 66 | 67 | expect(actual).toMatchInlineSnapshot(` 68 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 69 | export type WithContext = T & { 70 | "@context": "https://schema.org"; 71 | }; 72 | export interface Graph { 73 | "@context": "https://schema.org"; 74 | "@graph": readonly Thing[]; 75 | } 76 | type SchemaValue = T | readonly T[]; 77 | type IdReference = { 78 | /** IRI identifying the canonical address of this object. */ 79 | "@id": string; 80 | }; 81 | type InputActionConstraints = Partial<{ 82 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 83 | }>; 84 | type OutputActionConstraints = Partial<{ 85 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 86 | }>; 87 | /** Provides input and output action constraints for an action. */ 88 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 89 | 90 | export type Number = number | \`\${number}\`; 91 | 92 | export type Text = string; 93 | 94 | interface CarBase extends ThingBase { 95 | "doorNumber"?: SchemaValue; 96 | } 97 | interface CarLeaf extends CarBase { 98 | "@type": "Car"; 99 | } 100 | export type Car = CarLeaf; 101 | 102 | interface PersonLikeBase extends ThingBase { 103 | "height"?: SchemaValue; 104 | } 105 | interface PersonLikeLeaf extends PersonLikeBase { 106 | "@type": "PersonLike"; 107 | } 108 | export type PersonLike = PersonLikeLeaf; 109 | 110 | interface ThingBase extends Partial { 111 | "name"?: SchemaValue; 112 | } 113 | interface ThingLeaf extends ThingBase { 114 | "@type": "Thing"; 115 | } 116 | export type Thing = ThingLeaf | Car | PersonLike; 117 | 118 | " 119 | `); 120 | }); 121 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/property_edge_cases_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual, actualLogs} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | `, 37 | [ 38 | '--ontology', 39 | `https://fake.com/${basename(import.meta.url)}.nt`, 40 | `--verbose`, 41 | ], 42 | ); 43 | 44 | expect(actual).toMatchInlineSnapshot(` 45 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 46 | export type WithContext = T & { 47 | "@context": "https://schema.org"; 48 | }; 49 | export interface Graph { 50 | "@context": "https://schema.org"; 51 | "@graph": readonly Thing[]; 52 | } 53 | type SchemaValue = T | readonly T[]; 54 | type IdReference = { 55 | /** IRI identifying the canonical address of this object. */ 56 | "@id": string; 57 | }; 58 | type InputActionConstraints = Partial<{ 59 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 60 | }>; 61 | type OutputActionConstraints = Partial<{ 62 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 63 | }>; 64 | /** Provides input and output action constraints for an action. */ 65 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 66 | 67 | export type Text = string; 68 | 69 | interface ThingBase extends Partial { 70 | "knows"?: SchemaValue; 71 | "name"?: SchemaValue; 72 | } 73 | interface ThingLeaf extends ThingBase { 74 | "@type": "Thing"; 75 | } 76 | export type Thing = ThingLeaf; 77 | 78 | " 79 | `); 80 | expect(actualLogs).toMatchInlineSnapshot(` 81 | "Loading Ontology from URL: https://fake.com/property_edge_cases_test.ts.nt 82 | Got Response 200: Ok. 83 | Still unadded for property: name: 84 | (sameAs name) 85 | " 86 | `); 87 | }); 88 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/quantities_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | "Quantity" . 36 | . 37 | . 38 | "Intangible" . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | . 46 | . 47 | `, 48 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 49 | ); 50 | 51 | expect(actual).toMatchInlineSnapshot(` 52 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 53 | export type WithContext = T & { 54 | "@context": "https://schema.org"; 55 | }; 56 | export interface Graph { 57 | "@context": "https://schema.org"; 58 | "@graph": readonly Thing[]; 59 | } 60 | type SchemaValue = T | readonly T[]; 61 | type IdReference = { 62 | /** IRI identifying the canonical address of this object. */ 63 | "@id": string; 64 | }; 65 | type InputActionConstraints = Partial<{ 66 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 67 | }>; 68 | type OutputActionConstraints = Partial<{ 69 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 70 | }>; 71 | /** Provides input and output action constraints for an action. */ 72 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 73 | 74 | export type Text = string; 75 | 76 | interface DistanceLeaf extends ThingBase { 77 | "@type": "Distance"; 78 | } 79 | export type Distance = DistanceLeaf | string; 80 | 81 | interface DurationLeaf extends ThingBase { 82 | "@type": "Duration"; 83 | } 84 | export type Duration = DurationLeaf | string; 85 | 86 | interface EnergyLeaf extends ThingBase { 87 | "@type": "Energy"; 88 | } 89 | export type Energy = EnergyLeaf | string; 90 | 91 | interface IntangibleLeaf extends ThingBase { 92 | "@type": "Intangible"; 93 | } 94 | export type Intangible = IntangibleLeaf | Quantity; 95 | 96 | interface MassLeaf extends ThingBase { 97 | "@type": "Mass"; 98 | } 99 | export type Mass = MassLeaf | string; 100 | 101 | interface QuantityLeaf extends ThingBase { 102 | "@type": "Quantity"; 103 | } 104 | export type Quantity = QuantityLeaf | Distance | Duration | Energy | Mass | string; 105 | 106 | interface ThingBase extends Partial { 107 | "name"?: SchemaValue; 108 | } 109 | interface ThingLeaf extends ThingBase { 110 | "@type": "Thing"; 111 | } 112 | export type Thing = ThingLeaf | Intangible; 113 | 114 | " 115 | `); 116 | }); 117 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/role_simple_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | "Represents additional information about a relationship or property. For example a Role can be used to say that a 'member' role linking some SportsTeam to a player occurred during a particular time period. Or that a Person's 'actor' role in a Movie was for some particular characterName. Such properties can be attached to a Role entity, which is then associated with the main entities using ordinary properties like 'member' or 'actor'.\\n\\nSee also [blog post](http://blog.schema.org/2014/06/introducing-role.html)." . 34 | . 35 | "Role" . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | `, 45 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 46 | ); 47 | 48 | expect(actual).toMatchInlineSnapshot(` 49 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 50 | export type WithContext = T & { 51 | "@context": "https://schema.org"; 52 | }; 53 | export interface Graph { 54 | "@context": "https://schema.org"; 55 | "@graph": readonly Thing[]; 56 | } 57 | type SchemaValue = T | Role | readonly (T | Role)[]; 58 | type IdReference = { 59 | /** IRI identifying the canonical address of this object. */ 60 | "@id": string; 61 | }; 62 | type InputActionConstraints = Partial<{ 63 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 64 | }>; 65 | type OutputActionConstraints = Partial<{ 66 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 67 | }>; 68 | /** Provides input and output action constraints for an action. */ 69 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 70 | 71 | interface DateTimeBase extends Partial { 72 | } 73 | interface DateTimeLeaf extends DateTimeBase { 74 | "@type": "DateTime"; 75 | } 76 | export type DateTime = DateTimeLeaf | string; 77 | 78 | interface RoleBase extends ThingBase { 79 | "startDate"?: SchemaValue; 80 | } 81 | type RoleLeaf = RoleBase & { 82 | "@type": "Role"; 83 | } & { 84 | [key in TProperty]: TContent; 85 | }; 86 | /** 87 | * Represents additional information about a relationship or property. For example a Role can be used to say that a 'member' role linking some SportsTeam to a player occurred during a particular time period. Or that a Person's 'actor' role in a Movie was for some particular characterName. Such properties can be attached to a Role entity, which is then associated with the main entities using ordinary properties like 'member' or 'actor'. 88 | * 89 | * See also {@link http://blog.schema.org/2014/06/introducing-role.html blog post}. 90 | */ 91 | export type Role = RoleLeaf; 92 | 93 | export type Text = string; 94 | 95 | interface IntangibleLeaf extends ThingBase { 96 | "@type": "Intangible"; 97 | } 98 | export type Intangible = IntangibleLeaf | Role; 99 | 100 | interface ThingBase extends Partial { 101 | "name"?: SchemaValue; 102 | } 103 | interface ThingLeaf extends ThingBase { 104 | "@type": "Thing"; 105 | } 106 | export type Thing = ThingLeaf | Intangible; 107 | 108 | " 109 | `); 110 | }); 111 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/simple_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | `, 34 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 35 | ); 36 | 37 | expect(actual).toMatchInlineSnapshot(` 38 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 39 | export type WithContext = T & { 40 | "@context": "https://schema.org"; 41 | }; 42 | export interface Graph { 43 | "@context": "https://schema.org"; 44 | "@graph": readonly Thing[]; 45 | } 46 | type SchemaValue = T | readonly T[]; 47 | type IdReference = { 48 | /** IRI identifying the canonical address of this object. */ 49 | "@id": string; 50 | }; 51 | type InputActionConstraints = Partial<{ 52 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 53 | }>; 54 | type OutputActionConstraints = Partial<{ 55 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 56 | }>; 57 | /** Provides input and output action constraints for an action. */ 58 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 59 | 60 | export type Text = string; 61 | 62 | interface ThingBase extends Partial { 63 | "name"?: SchemaValue; 64 | } 65 | interface ThingLeaf extends ThingBase { 66 | "@type": "Thing"; 67 | } 68 | export type Thing = ThingLeaf; 69 | 70 | " 71 | `); 72 | }); 73 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/sorted_enum_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | "A letter!" . 32 | . 33 | "A Thing!" . 34 | `, 35 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 36 | ); 37 | 38 | expect(actual).toMatchInlineSnapshot(` 39 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 40 | export type WithContext = T & { 41 | "@context": "https://schema.org"; 42 | }; 43 | export interface Graph { 44 | "@context": "https://schema.org"; 45 | "@graph": readonly Thing[]; 46 | } 47 | type SchemaValue = T | readonly T[]; 48 | type IdReference = { 49 | /** IRI identifying the canonical address of this object. */ 50 | "@id": string; 51 | }; 52 | type InputActionConstraints = Partial<{ 53 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 54 | }>; 55 | type OutputActionConstraints = Partial<{ 56 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 57 | }>; 58 | /** Provides input and output action constraints for an action. */ 59 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 60 | 61 | interface ThingBase extends Partial { 62 | } 63 | interface ThingLeaf extends ThingBase { 64 | "@type": "Thing"; 65 | } 66 | /** A Thing! */ 67 | export type Thing = "http://schema.org/a" | "https://schema.org/a" | "a" | "http://schema.org/b" | "https://schema.org/b" | "b" | "http://schema.org/c" | "https://schema.org/c" | "c" | "http://schema.org/d" | "https://schema.org/d" | "d" | ThingLeaf; 68 | 69 | " 70 | `); 71 | }); 72 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/sorted_props_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | `, 43 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 44 | ); 45 | 46 | expect(actual).toMatchInlineSnapshot(` 47 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 48 | export type WithContext = T & { 49 | "@context": "https://schema.org"; 50 | }; 51 | export interface Graph { 52 | "@context": "https://schema.org"; 53 | "@graph": readonly Thing[]; 54 | } 55 | type SchemaValue = T | readonly T[]; 56 | type IdReference = { 57 | /** IRI identifying the canonical address of this object. */ 58 | "@id": string; 59 | }; 60 | type InputActionConstraints = Partial<{ 61 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 62 | }>; 63 | type OutputActionConstraints = Partial<{ 64 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 65 | }>; 66 | /** Provides input and output action constraints for an action. */ 67 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 68 | 69 | export type Text = string; 70 | 71 | interface ThingBase extends Partial { 72 | "a"?: SchemaValue; 73 | "b"?: SchemaValue; 74 | "c"?: SchemaValue; 75 | "d"?: SchemaValue; 76 | } 77 | interface ThingLeaf extends ThingBase { 78 | "@type": "Thing"; 79 | } 80 | export type Thing = ThingLeaf; 81 | 82 | " 83 | `); 84 | }); 85 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/sorted_proptypes_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | . 46 | . 47 | . 48 | . 49 | . 50 | `, 51 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 52 | ); 53 | 54 | expect(actual).toMatchInlineSnapshot(` 55 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 56 | export type WithContext = T & { 57 | "@context": "https://schema.org"; 58 | }; 59 | export interface Graph { 60 | "@context": "https://schema.org"; 61 | "@graph": readonly Thing[]; 62 | } 63 | type SchemaValue = T | readonly T[]; 64 | type IdReference = { 65 | /** IRI identifying the canonical address of this object. */ 66 | "@id": string; 67 | }; 68 | type InputActionConstraints = Partial<{ 69 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 70 | }>; 71 | type OutputActionConstraints = Partial<{ 72 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 73 | }>; 74 | /** Provides input and output action constraints for an action. */ 75 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 76 | 77 | export type Boolean = "http://schema.org/False" | "https://schema.org/False" | "False" | "http://schema.org/True" | "https://schema.org/True" | "True" | boolean; 78 | 79 | export type Date = string; 80 | 81 | export type DateTime = string; 82 | 83 | export type Number = number | \`\${number}\`; 84 | 85 | export type Text = string; 86 | 87 | export type Time = string; 88 | 89 | interface ThingBase extends Partial { 90 | "a"?: SchemaValue; 91 | } 92 | interface ThingLeaf extends ThingBase { 93 | "@type": "Thing"; 94 | } 95 | export type Thing = ThingLeaf; 96 | 97 | " 98 | `); 99 | }); 100 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | "A type of medical procedure that involves invasive surgical techniques." . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | . 46 | . 47 | `, 48 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 49 | ); 50 | 51 | expect(actual).toMatchInlineSnapshot(` 52 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 53 | export type WithContext = T & { 54 | "@context": "https://schema.org"; 55 | }; 56 | export interface Graph { 57 | "@context": "https://schema.org"; 58 | "@graph": readonly Thing[]; 59 | } 60 | type SchemaValue = T | readonly T[]; 61 | type IdReference = { 62 | /** IRI identifying the canonical address of this object. */ 63 | "@id": string; 64 | }; 65 | type InputActionConstraints = Partial<{ 66 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 67 | }>; 68 | type OutputActionConstraints = Partial<{ 69 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 70 | }>; 71 | /** Provides input and output action constraints for an action. */ 72 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 73 | 74 | interface EnumerationLeaf extends ThingBase { 75 | "@type": "Enumeration"; 76 | } 77 | export type Enumeration = EnumerationLeaf | MedicalEnumeration; 78 | 79 | interface IntangibleLeaf extends ThingBase { 80 | "@type": "Intangible"; 81 | } 82 | export type Intangible = IntangibleLeaf | Enumeration; 83 | 84 | interface MedicalEnumerationLeaf extends ThingBase { 85 | "@type": "MedicalEnumeration"; 86 | } 87 | export type MedicalEnumeration = MedicalEnumerationLeaf | MedicalProcedureType; 88 | 89 | interface MedicalProcedureLeaf extends ThingBase { 90 | "@type": "MedicalProcedure"; 91 | } 92 | export type MedicalProcedure = MedicalProcedureLeaf | SurgicalProcedure; 93 | 94 | interface MedicalProcedureTypeLeaf extends ThingBase { 95 | "@type": "MedicalProcedureType"; 96 | } 97 | export type MedicalProcedureType = "http://schema.org/SurgicalProcedure" | "https://schema.org/SurgicalProcedure" | "SurgicalProcedure" | MedicalProcedureTypeLeaf; 98 | 99 | interface SurgicalProcedureLeaf extends ThingBase { 100 | "@type": "SurgicalProcedure"; 101 | } 102 | /** A type of medical procedure that involves invasive surgical techniques. */ 103 | export type SurgicalProcedure = SurgicalProcedureLeaf; 104 | 105 | interface ThingBase extends Partial { 106 | } 107 | interface ThingLeaf extends ThingBase { 108 | "@type": "Thing"; 109 | } 110 | export type Thing = ThingLeaf | Intangible | MedicalProcedure; 111 | 112 | " 113 | `); 114 | }); 115 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_v2_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | . 31 | "A type of medical procedure that involves invasive surgical techniques." . 32 | . 33 | . 34 | . 35 | . 36 | . 37 | . 38 | . 39 | . 40 | . 41 | . 42 | . 43 | . 44 | . 45 | . 46 | . 47 | `, 48 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 49 | ); 50 | 51 | expect(actual).toMatchInlineSnapshot(` 52 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 53 | export type WithContext = T & { 54 | "@context": "https://schema.org"; 55 | }; 56 | export interface Graph { 57 | "@context": "https://schema.org"; 58 | "@graph": readonly Thing[]; 59 | } 60 | type SchemaValue = T | readonly T[]; 61 | type IdReference = { 62 | /** IRI identifying the canonical address of this object. */ 63 | "@id": string; 64 | }; 65 | type InputActionConstraints = Partial<{ 66 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 67 | }>; 68 | type OutputActionConstraints = Partial<{ 69 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 70 | }>; 71 | /** Provides input and output action constraints for an action. */ 72 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 73 | 74 | interface EnumerationLeaf extends ThingBase { 75 | "@type": "Enumeration"; 76 | } 77 | export type Enumeration = EnumerationLeaf | MedicalEnumeration; 78 | 79 | interface IntangibleLeaf extends ThingBase { 80 | "@type": "Intangible"; 81 | } 82 | export type Intangible = IntangibleLeaf | Enumeration; 83 | 84 | interface MedicalEnumerationLeaf extends ThingBase { 85 | "@type": "MedicalEnumeration"; 86 | } 87 | export type MedicalEnumeration = MedicalEnumerationLeaf | MedicalProcedureType; 88 | 89 | interface MedicalProcedureLeaf extends ThingBase { 90 | "@type": "MedicalProcedure"; 91 | } 92 | export type MedicalProcedure = MedicalProcedureLeaf | SurgicalProcedure; 93 | 94 | interface MedicalProcedureTypeLeaf extends ThingBase { 95 | "@type": "MedicalProcedureType"; 96 | } 97 | export type MedicalProcedureType = "http://schema.org/SurgicalProcedure" | "https://schema.org/SurgicalProcedure" | "SurgicalProcedure" | MedicalProcedureTypeLeaf; 98 | 99 | interface SurgicalProcedureLeaf extends ThingBase { 100 | "@type": "SurgicalProcedure"; 101 | } 102 | /** A type of medical procedure that involves invasive surgical techniques. */ 103 | export type SurgicalProcedure = SurgicalProcedureLeaf; 104 | 105 | interface ThingBase extends Partial { 106 | } 107 | interface ThingLeaf extends ThingBase { 108 | "@type": "Thing"; 109 | } 110 | export type Thing = ThingLeaf | Intangible | MedicalProcedure; 111 | 112 | " 113 | `); 114 | }); 115 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/transitive_class_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | . 28 | . 29 | . 30 | "ABC" . 31 | . 32 | "ABC" . 33 | . 34 | . 35 | . 36 | "Data type: Text." . 37 | `, 38 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 39 | ); 40 | 41 | expect(actual).toMatchInlineSnapshot(` 42 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 43 | export type WithContext = T & { 44 | "@context": "https://schema.org"; 45 | }; 46 | export interface Graph { 47 | "@context": "https://schema.org"; 48 | "@graph": readonly Thing[]; 49 | } 50 | type SchemaValue = T | readonly T[]; 51 | type IdReference = { 52 | /** IRI identifying the canonical address of this object. */ 53 | "@id": string; 54 | }; 55 | type InputActionConstraints = Partial<{ 56 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 57 | }>; 58 | type OutputActionConstraints = Partial<{ 59 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 60 | }>; 61 | /** Provides input and output action constraints for an action. */ 62 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 63 | 64 | /** Data type: Text. */ 65 | export type Text = string; 66 | 67 | interface PersonLeaf extends ThingBase { 68 | "@type": "Person"; 69 | } 70 | /** ABC */ 71 | export type Person = PersonLeaf | string; 72 | 73 | interface ThingBase extends Partial { 74 | "name"?: SchemaValue; 75 | } 76 | interface ThingLeaf extends ThingBase { 77 | "@type": "Thing"; 78 | } 79 | /** ABC */ 80 | export type Thing = ThingLeaf | Person; 81 | 82 | " 83 | `); 84 | }); 85 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/unknown_wellknown_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | await expect( 26 | inlineCli( 27 | ` 28 | . 29 | . 30 | . 31 | . 32 | . 33 | . 34 | . 35 | . 36 | `, 37 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 38 | ), 39 | ).rejects.toThrow('must have corresponding well-known type.'); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/baselines/url_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview Baseline tests are a set of tests (in tests/baseline/) that 17 | * correspond to full comparisons of a generate .ts output based on a set of 18 | * Triples representing an entire ontology. 19 | */ 20 | import {basename} from 'path'; 21 | 22 | import {inlineCli} from '../helpers/main_driver.js'; 23 | 24 | test(`baseline_${basename(import.meta.url)}`, async () => { 25 | const {actual} = await inlineCli( 26 | ` 27 | "Data type: URL." . 28 | . 29 | "URL" . 30 | . 31 | . 32 | . 33 | `, 34 | ['--ontology', `https://fake.com/${basename(import.meta.url)}.nt`], 35 | ); 36 | 37 | expect(actual).toMatchInlineSnapshot(` 38 | "/** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ 39 | export type WithContext = T & { 40 | "@context": "https://schema.org"; 41 | }; 42 | export interface Graph { 43 | "@context": "https://schema.org"; 44 | "@graph": readonly Thing[]; 45 | } 46 | type SchemaValue = T | readonly T[]; 47 | type IdReference = { 48 | /** IRI identifying the canonical address of this object. */ 49 | "@id": string; 50 | }; 51 | type InputActionConstraints = Partial<{ 52 | [K in Exclude as \`\${string & K}-input\`]: PropertyValueSpecification | string; 53 | }>; 54 | type OutputActionConstraints = Partial<{ 55 | [K in Exclude as \`\${string & K}-output\`]: PropertyValueSpecification | string; 56 | }>; 57 | /** Provides input and output action constraints for an action. */ 58 | export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; 59 | 60 | export type Text = URL | string; 61 | 62 | /** Data type: URL. */ 63 | export type URL = string; 64 | 65 | " 66 | `); 67 | }); 68 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/cli/args_logmessages_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | import {jest} from '@jest/globals'; 18 | 19 | import fs from 'fs/promises'; 20 | import {main} from '../../src/cli/internal/main.js'; 21 | import {SetLogger} from '../../src/logging/index.js'; 22 | 23 | describe('main Args logs', () => { 24 | let logs: string[]; 25 | let ResetLogger: undefined | (() => void) = undefined; 26 | 27 | beforeEach(() => { 28 | const mockFileLine = ` .\n`; 29 | jest 30 | .spyOn(fs, 'readFile') 31 | .mockImplementation(_ => Promise.resolve(mockFileLine)); 32 | 33 | logs = []; 34 | ResetLogger = SetLogger(msg => logs.push(msg)); 35 | }); 36 | afterEach(() => { 37 | ResetLogger && ResetLogger(); 38 | }); 39 | 40 | it(`the path it is loading from`, async () => { 41 | await main(noop, ['--file', `ontology-file.nt`, `--verbose`]); 42 | expect(logs.join('')).toMatchInlineSnapshot( 43 | `"Loading Ontology from path: ontology-file.nt"`, 44 | ); 45 | }); 46 | }); 47 | 48 | function noop() {} 49 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/cli/args_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {jest} from '@jest/globals'; 17 | 18 | import {ParseFlags} from '../../src/cli/args.js'; 19 | import {ArgumentParser} from 'argparse'; 20 | 21 | describe('ParseFlags', () => { 22 | it('defaults', () => { 23 | const options = ParseFlags([]); 24 | expect(options).not.toBeUndefined(); 25 | expect(options.context).toBe('https://schema.org'); 26 | expect(options.deprecated).toBe(true); 27 | expect(options.verbose).toBe(false); 28 | expect(options.file).toBeUndefined(); 29 | 30 | expect(options.ontology).toBe( 31 | 'https://schema.org/version/latest/schemaorg-all-https.nt', 32 | ); 33 | }); 34 | 35 | it('custom ontology', () => { 36 | const options = ParseFlags(['--ontology', 'https://google.com/foo']); 37 | expect(options).not.toBeUndefined(); 38 | 39 | expect(options.ontology).toBe('https://google.com/foo'); 40 | }); 41 | 42 | it('custom file', () => { 43 | const options = ParseFlags(['--file', './ontology.nt']); 44 | expect(options).not.toBeUndefined(); 45 | 46 | expect(options.file).toBe('./ontology.nt'); 47 | }); 48 | 49 | describe('deprecated fields', () => { 50 | beforeEach(() => { 51 | jest.spyOn(ArgumentParser.prototype, 'exit').mockImplementation(e => { 52 | throw new Error(`${e}`); 53 | }); 54 | }); 55 | 56 | it('--layer', () => { 57 | expect(() => ParseFlags(['--layer', 'foo'])).toThrow(); 58 | }); 59 | 60 | it('--schema', () => { 61 | expect(() => ParseFlags(['--schema', 'bar'])).toThrow(); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/helpers/async.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | export function flush(): Promise { 19 | return new Promise(resolve => { 20 | setTimeout(resolve, 1); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/helpers/main_driver.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @fileoverview A simple runner around a mocked version of the CLI's main() 17 | * function, for testing. 18 | */ 19 | 20 | import {ClientRequest, IncomingMessage} from 'http'; 21 | import https from 'https'; 22 | 23 | import {main} from '../../src/cli/internal/main.js'; 24 | import {SetLogger, SetOptions} from '../../src/logging/index.js'; 25 | import {assert} from '../../src/util/assert.js'; 26 | 27 | import {flush} from './async.js'; 28 | 29 | export async function inlineCli( 30 | content: string, 31 | args: string[], 32 | ): Promise<{actual: string; actualLogs: string}> { 33 | // Restorables 34 | const realGet = https.get; 35 | let ResetLogger: undefined | (() => void) = undefined; 36 | 37 | try { 38 | // Controllers 39 | let innerOnData: (chunk: Buffer) => void; 40 | let innerOnEnd: () => void; 41 | 42 | const write = (s: string) => writes.push(s); 43 | 44 | ResetLogger = SetLogger((msg: string) => void logs.push(msg)); 45 | 46 | // TODO(eyas): A lot of the mocking here is due to the fact that https.get 47 | // cannot read local file:/// paths. If it were possible, the get mocking 48 | // would go away, making a lot of this much simpler. 49 | https.get = (( 50 | _: string, 51 | callback: (inc: IncomingMessage) => void, 52 | ): ClientRequest => { 53 | callback({ 54 | statusCode: 200, 55 | statusMessage: 'Ok', 56 | on: (event: string, listener: (arg?: unknown) => void) => { 57 | if (event === 'data') innerOnData = listener; 58 | if (event === 'end') innerOnEnd = listener; 59 | }, 60 | } as IncomingMessage); 61 | return {on: () => {}} as unknown as ClientRequest; 62 | }) as typeof https.get; 63 | 64 | // Outputs 65 | const writes: string[] = []; 66 | const logs: string[] = []; 67 | 68 | const wholeProgram = main(write, args); 69 | await flush(); 70 | 71 | assert(innerOnData!); 72 | assert(innerOnEnd!); 73 | 74 | innerOnData(Buffer.from(content)); 75 | innerOnEnd(); 76 | 77 | await wholeProgram; 78 | 79 | return { 80 | actual: writes.join(''), 81 | actualLogs: logs.join('\n') + '\n', 82 | }; 83 | } finally { 84 | https.get = realGet; 85 | 86 | // Always reset verbosity settings. 87 | SetOptions({verbose: false}); 88 | ResetLogger && ResetLogger(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/helpers/make_class.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {NamedNode} from 'n3'; 17 | import {Property, PropertyType} from '../../src/index.js'; 18 | import {Class, ClassMap} from '../../src/ts/class.js'; 19 | 20 | export function makeClass(url: string): Class { 21 | return new Class(new NamedNode(url)); 22 | } 23 | 24 | export function makeProperty(url: string): Property { 25 | const u = new NamedNode(url); 26 | return new Property(u, new PropertyType(u)); 27 | } 28 | 29 | export function makeClassMap(...classes: Class[]): ClassMap { 30 | return new Map(classes.map(cls => [cls.subject.id, cls])); 31 | } 32 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/logging/index_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {jest} from '@jest/globals'; 17 | import type {Mock} from 'jest-mock'; 18 | 19 | import {Log, SetLogger, SetOptions} from '../../src/logging/index.js'; 20 | 21 | describe('Log', () => { 22 | let logErr: Mock; 23 | let ResetLogger: undefined | (() => void) = undefined; 24 | 25 | beforeEach(() => { 26 | logErr = jest.fn(); 27 | ResetLogger = SetLogger(logErr); 28 | }); 29 | 30 | afterEach(() => { 31 | ResetLogger && ResetLogger(); 32 | }); 33 | 34 | it("doesn't log by default", () => { 35 | Log('Foo'); 36 | expect(logErr).not.toBeCalled(); 37 | }); 38 | 39 | it("doesn't log when verbose=false", () => { 40 | SetOptions({verbose: false}); 41 | Log('Foo'); 42 | expect(logErr).not.toBeCalled(); 43 | }); 44 | 45 | it('logs when verbose=true', () => { 46 | SetOptions({verbose: true}); 47 | Log('Foo'); 48 | expect(logErr).toBeCalledWith('Foo'); 49 | }); 50 | 51 | it('stops logging after turned off', () => { 52 | SetOptions({verbose: true}); 53 | Log('Foo'); 54 | SetOptions({verbose: false}); 55 | Log('Bar'); 56 | 57 | expect(logErr).toBeCalledWith('Foo'); 58 | expect(logErr).not.toBeCalledWith('Bar'); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/ts/enum_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {jest} from '@jest/globals'; 17 | import {NamedNode} from 'n3'; 18 | 19 | import {EnumValue} from '../../src/ts/enum.js'; 20 | import {makeClass, makeClassMap} from '../helpers/make_class.js'; 21 | 22 | describe('EnumValue', () => { 23 | describe('constructor', () => { 24 | it('Throws when referencing a non-existent type', () => { 25 | const map = makeClassMap( 26 | makeClass('https://schema.org/Foo'), 27 | makeClass('https://schema.org/Bar'), 28 | makeClass('https://schema.org/Baz'), 29 | ); 30 | expect( 31 | () => 32 | new EnumValue( 33 | new NamedNode('https://schema.org/Wednesday'), 34 | [new NamedNode('https://schema.org/DayOfWeek')], 35 | map, 36 | ), 37 | ).toThrowError("Couldn't find"); 38 | }); 39 | 40 | it('Works fine when called for plain enum', () => { 41 | const dayOfWeek = makeClass('https://schema.org/DayOfWeek'); 42 | const addEnum = jest.fn(); 43 | dayOfWeek.addEnum = addEnum; 44 | 45 | const map = makeClassMap( 46 | makeClass('https://schema.org/Foo'), 47 | makeClass('https://schema.org/Bar'), 48 | dayOfWeek, 49 | ); 50 | 51 | const myEnum = new EnumValue( 52 | new NamedNode('https://schema.org/Wednesday'), 53 | [new NamedNode('https://schema.org/DayOfWeek')], 54 | map, 55 | ); 56 | 57 | expect(addEnum).toBeCalledWith(myEnum); 58 | }); 59 | 60 | it('Works fine when called for an enum/class', () => { 61 | const medicalProcedureType = makeClass( 62 | 'https://schema.org/MedicalProcedureType', 63 | ); 64 | const addEnum = jest.fn(); 65 | medicalProcedureType.addEnum = addEnum; 66 | 67 | const map = makeClassMap( 68 | makeClass('https://schema.org/Foo'), 69 | makeClass('https://schema.org/Bar'), 70 | medicalProcedureType, 71 | ); 72 | 73 | const myEnum = new EnumValue( 74 | new NamedNode('https://schema.org/SurgicalProcedure'), 75 | [ 76 | new NamedNode('https://schema.org/MedicalProcedureType'), 77 | new NamedNode('http://www.w3.org/2000/01/rdf-schema#Class'), 78 | ], 79 | map, 80 | ); 81 | 82 | expect(addEnum).toBeCalledWith(myEnum); 83 | }); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/ts/names_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import {NamedNode} from 'n3'; 17 | import {toClassName} from '../../src/ts/util/names.js'; 18 | 19 | function parseNamed(url: string) { 20 | return new NamedNode(url); 21 | } 22 | 23 | describe('toClassName', () => { 24 | it('operates normally, with typical inputs', () => { 25 | expect(toClassName(parseNamed('https://schema.org/Person'))).toBe('Person'); 26 | expect(toClassName(parseNamed('https://schema.org/Person3'))).toBe( 27 | 'Person3', 28 | ); 29 | expect(toClassName(parseNamed('http://schema.org/Person'))).toBe('Person'); 30 | expect( 31 | toClassName(parseNamed('http://schema.org/Organization4Organization')), 32 | ).toBe('Organization4Organization'); 33 | }); 34 | 35 | it('handles illegal TypeScript identifier characters', () => { 36 | expect(toClassName(parseNamed('https://schema.org/Person-4'))).toBe( 37 | 'Person_4', 38 | ); 39 | expect(toClassName(parseNamed('https://schema.org/Person%4'))).toBe( 40 | 'Person_4', 41 | ); 42 | expect(toClassName(parseNamed('https://schema.org/Person%204'))).toBe( 43 | 'Person_4', 44 | ); 45 | expect(toClassName(parseNamed('https://schema.org/Person, 4'))).toBe( 46 | 'Person__4', 47 | ); 48 | 49 | expect(toClassName(parseNamed('https://schema.org/3DModel'))).toBe( 50 | '_3DModel', 51 | ); 52 | expect(toClassName(parseNamed('https://schema.org/3DModel-5'))).toBe( 53 | '_3DModel_5', 54 | ); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/ts/property_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import {Literal, NamedNode, Quad} from 'n3'; 18 | import {PropertyType} from '../../src/ts/property.js'; 19 | import {makeClass, makeClassMap} from '../helpers/make_class.js'; 20 | 21 | describe('PropertyType', () => { 22 | let prop: PropertyType; 23 | 24 | beforeEach(() => { 25 | prop = new PropertyType(new NamedNode('https://schema.org/name')); 26 | }); 27 | 28 | it('initial properties when empty', () => { 29 | expect(prop.comment).toBeUndefined(); 30 | expect(prop.deprecated).toBe(false); 31 | }); 32 | 33 | describe('add', () => { 34 | describe('rangeIncludes', () => { 35 | const rangeIncludes = () => 36 | new NamedNode('https://schema.org/rangeIncludes'); 37 | 38 | it('non-type rangeIncludes object fails', () => { 39 | expect(() => 40 | prop.add( 41 | new Quad( 42 | new NamedNode('https://schema.org/Foo'), 43 | rangeIncludes(), 44 | new Literal('"foo"'), 45 | ), 46 | new Map(), 47 | ), 48 | ).toThrowError('Type expected to be a UrlNode'); 49 | }); 50 | 51 | it("type rangeIncludes object fails when class doesn't exist", () => { 52 | expect(() => 53 | prop.add( 54 | new Quad( 55 | new NamedNode('https://schema.org/Foo'), 56 | rangeIncludes(), 57 | new NamedNode('https://schema.org/Thing'), 58 | ), 59 | new Map(), 60 | ), 61 | ).toThrowError('Could not find class for https://schema.org/Thing'); 62 | }); 63 | 64 | it('type rangeIncludes object succeeds', () => { 65 | expect( 66 | prop.add( 67 | new Quad( 68 | new NamedNode('https://schema.org/Foo'), 69 | rangeIncludes(), 70 | new NamedNode('https://schema.org/Thing'), 71 | ), 72 | makeClassMap(makeClass('https://schema.org/Thing')), 73 | ), 74 | ).toBe(true); 75 | }); 76 | }); 77 | }); 78 | 79 | describe('domainIncludes', () => { 80 | const domainIncludes = () => 81 | new NamedNode('https://schema.org/domainIncludes'); 82 | it('failed lookup throws', () => { 83 | const classes = makeClassMap(makeClass('https://schema.org/Person')); 84 | expect(() => 85 | prop.add( 86 | new Quad( 87 | new NamedNode('https://schema.org/Foo'), 88 | domainIncludes(), 89 | new NamedNode('https://schema.org/Thing'), 90 | ), 91 | classes, 92 | ), 93 | ).toThrowError('Could not find class'); 94 | }); 95 | 96 | it('real lookup works', () => { 97 | const classes = makeClassMap(makeClass('https://schema.org/Person')); 98 | expect( 99 | prop.add( 100 | new Quad( 101 | new NamedNode('https://schema.org/Foo'), 102 | domainIncludes(), 103 | new NamedNode('https://schema.org/Person'), 104 | ), 105 | classes, 106 | ), 107 | ).toBe(true); 108 | }); 109 | }); 110 | 111 | describe('supersededBy', () => { 112 | it('always works', () => { 113 | expect( 114 | prop.add( 115 | new Quad( 116 | new NamedNode('https://schema.org/Foo'), 117 | new NamedNode('https://schema.org/supersededBy'), 118 | new NamedNode('https://schema.org/Person'), 119 | ), 120 | new Map(), 121 | ), 122 | ).toBe(true); 123 | 124 | expect(prop.comment).toMatch(/@deprecated/g); 125 | expect(prop.deprecated).toBe(true); 126 | }); 127 | }); 128 | 129 | describe('comment', () => { 130 | const comment = () => 131 | new NamedNode('http://www.w3.org/2000/01/rdf-schema#comment'); 132 | 133 | it('works with string', () => { 134 | expect( 135 | prop.add( 136 | new Quad( 137 | new NamedNode('https://schema.org/Foo'), 138 | comment(), 139 | new Literal('"foo"'), 140 | ), 141 | new Map(), 142 | ), 143 | ).toBe(true); 144 | 145 | expect(prop.comment).toMatch(/foo/g); 146 | }); 147 | 148 | it('only supports strings as comments', () => { 149 | expect(() => 150 | prop.add( 151 | new Quad( 152 | new NamedNode('https://schema.org/Foo'), 153 | comment(), 154 | new NamedNode('http://schema.org/Amazing'), 155 | ), 156 | new Map(), 157 | ), 158 | ).toThrowError('non-string object'); 159 | }); 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig-base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/test", 5 | "rootDir": "." 6 | }, 7 | "references": [ 8 | { 9 | "path": "../src" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/schema-dts-gen/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "references": [ 4 | { 5 | "path": "./src" 6 | }, 7 | { 8 | "path": "./test" 9 | } 10 | ], 11 | "compilerOptions": { 12 | "outDir": "./dist" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/schema-dts/.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | -------------------------------------------------------------------------------- /packages/schema-dts/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/google/schema-dts/actions/workflows/ci.yml/badge.svg)](https://github.com/google/schema-dts/actions/workflows/ci.yml) 2 | [![Coverage Status](https://coveralls.io/repos/github/google/schema-dts/badge.svg?branch=main)](https://coveralls.io/github/google/schema-dts?branch=main) 3 | [![schema-dts npm version](https://badge.fury.io/js/schema-dts.svg)](https://www.npmjs.com/package/schema-dts) 4 | 5 | # schema-dts 6 | 7 | JSON-LD TypeScript types for Schema.org vocabulary. 8 | 9 | **schema-dts** provides TypeScript definitions for 10 | [Schema.org](https://schema.org/) vocabulary in JSON-LD format. The typings are 11 | exposed as complete sets of discriminated type unions, allowing for easy 12 | completions and stricter validation. 13 | 14 | ![Example of Code Completion using schema-dts](https://raw.githubusercontent.com/google/schema-dts/HEAD/example-1.gif) 15 | 16 | Note: This is not an officially supported Google product. 17 | 18 | ## Usage 19 | 20 | To use the typings for your project, simply add the `schema-dts` NPM package to 21 | your project: 22 | 23 | ```command 24 | npm install schema-dts 25 | ``` 26 | 27 | Then you can use it by importing `"schema-dts"`. 28 | 29 | ## Examples 30 | 31 | ### Defining Simple Properties 32 | 33 | ```ts 34 | import type {Person} from 'schema-dts'; 35 | 36 | const inventor: Person = { 37 | '@type': 'Person', 38 | name: 'Grace Hopper', 39 | disambiguatingDescription: 'American computer scientist', 40 | birthDate: '1906-12-09', 41 | deathDate: '1992-01-01', 42 | awards: [ 43 | 'Presidential Medal of Freedom', 44 | 'National Medal of Technology and Innovation', 45 | 'IEEE Emanuel R. Piore Award', 46 | ], 47 | }; 48 | ``` 49 | 50 | ### Using 'Context' 51 | 52 | JSON-LD requires a `"@context"` property to be set on the top-level JSON object, 53 | to describe the URIs represeting the types and properties being referenced. 54 | schema-dts provides the `WithContext` type to facilitate this. 55 | 56 | ```ts 57 | import type {Organization, Thing, WithContext} from 'schema-dts'; 58 | 59 | export function JsonLd(json: WithContext): string { 60 | return ``; 63 | } 64 | 65 | export const MY_ORG = JsonLd({ 66 | '@context': 'https://schema.org', 67 | '@type': 'Corporation', 68 | name: 'Google LLC', 69 | }); 70 | ``` 71 | 72 | ### Graphs and IDs 73 | 74 | JSON-LD supports `'@graph'` objects that have richer interconnected links 75 | between the nodes. You can do that easily in `schema-dts` by using the `Graph` 76 | type. 77 | 78 | Notice that any node can have an `@id` when defining it. And you can reference 79 | the same node from different places by simply using an ID stub, for example 80 | `{ '@id': 'https://my.site/about/#page }` below is an ID stub. 81 | 82 | The example below shows potential JSON-LD for an About page. It includes 83 | definitions of Alyssa P. Hacker (the author & subject of the page), the specific 84 | page in this URL, and the website it belongs to. Some objects are still defined 85 | as inline nested objects (e.g. Occupation), since they are only referenced by 86 | their parent. Other objects are defined at the top-level with an `@id`, because 87 | multiple nodes refer to them. 88 | 89 | ```ts 90 | import type {Graph} from 'schema-dts'; 91 | 92 | const graph: Graph = { 93 | '@context': 'https://schema.org', 94 | '@graph': [ 95 | { 96 | '@type': 'Person', 97 | '@id': 'https://my.site/#alyssa', 98 | name: 'Alyssa P. Hacker', 99 | hasOccupation: { 100 | '@type': 'Occupation', 101 | name: 'LISP Hacker', 102 | qualifications: 'Knows LISP', 103 | }, 104 | mainEntityOfPage: {'@id': 'https://my.site/about/#page'}, 105 | subjectOf: {'@id': 'https://my.site/about/#page'}, 106 | }, 107 | { 108 | '@type': 'AboutPage', 109 | '@id': 'https://my.site/#site', 110 | url: 'https://my.site', 111 | name: "Alyssa P. Hacker's Website", 112 | inLanguage: 'en-US', 113 | description: 'The personal website of LISP legend Alyssa P. Hacker', 114 | mainEntity: {'@id': 'https://my.site/#alyssa'}, 115 | }, 116 | { 117 | '@type': 'WebPage', 118 | '@id': 'https://my.site/about/#page', 119 | url: 'https://my.site/about/', 120 | name: "About | Alyssa P. Hacker's Website", 121 | inLanguage: 'en-US', 122 | isPartOf: { 123 | '@id': 'https://my.site/#site', 124 | }, 125 | about: {'@id': 'https://my.site/#alyssa'}, 126 | mainEntity: {'@id': 'https://my.site/#alyssa'}, 127 | }, 128 | ], 129 | }; 130 | ``` 131 | -------------------------------------------------------------------------------- /packages/schema-dts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "schema-dts", 3 | "version": "1.1.5", 4 | "displayName": "schema-dts: Strongly-typed Schema.org vocabulary declarations", 5 | "description": "A TypeScript package with latest Schema.org Schema Typings", 6 | "author": "Eyas Sharaiha (https://eyas.sh/)", 7 | "maintainers": [ 8 | "Eyas Sharaiha (https://eyas.sh/)" 9 | ], 10 | "contributors": [ 11 | "Eyas Sharaiha (https://eyas.sh/)" 12 | ], 13 | "files": [ 14 | "dist/schema.d.ts", 15 | "dist/schema.js", 16 | "LICENSE", 17 | "README.md" 18 | ], 19 | "types": "./dist/schema.d.ts", 20 | "main": "./dist/schema.js", 21 | "devDependencies": { 22 | "mkdirp": "^3.0.1", 23 | "schema-dts-gen": "*" 24 | }, 25 | "keywords": [ 26 | "typescript", 27 | "tsd", 28 | "dts", 29 | "schema.org", 30 | "Semantic Web", 31 | "semantic-web", 32 | "Linked Data", 33 | "linked-data", 34 | "jsonld", 35 | "JSON-LD", 36 | "structured data", 37 | "structured-data" 38 | ], 39 | "homepage": "https://opensource.google/projects/schema-dts", 40 | "bugs": "https://github.com/google/schema-dts/issues", 41 | "repository": { 42 | "type": "git", 43 | "url": "https://github.com/google/schema-dts.git", 44 | "directory": "packages/schema-dts" 45 | }, 46 | "scripts": { 47 | "lint:eslint": "eslint test/**/*.ts", 48 | "prepare": "mkdirp lib/", 49 | "build:generate": "schema-dts-gen > lib/schema.ts", 50 | "build:compile": "tsc -p .", 51 | "build": "npm run build:generate && npm run build:compile", 52 | "test": "npm run build && tsc -p test/" 53 | }, 54 | "license": "Apache-2.0" 55 | } 56 | -------------------------------------------------------------------------------- /packages/schema-dts/test/easy.ts: -------------------------------------------------------------------------------- 1 | import {Thing} from '../dist/schema'; 2 | 3 | // "@type" is required 4 | // @ts-expect-error missing @type 5 | const _1: Thing = {}; 6 | 7 | // "@type" can be the requested tpye 8 | const _2: Thing = { 9 | '@type': 'Thing', 10 | }; 11 | 12 | // "@type" can be a sub-type 13 | const _3: Thing = { 14 | '@type': 'Person', 15 | }; 16 | 17 | // "@type" must be valid 18 | const _4: Thing = { 19 | // @ts-expect-error Invalid type 20 | '@type': 'Personz', 21 | }; 22 | 23 | // A narrow "@type" allows defining sub-properties 24 | const _5: Thing = { 25 | '@type': 'Person', 26 | name: 'a', 27 | additionalName: ['b', 'c', 'd'], 28 | }; 29 | 30 | // A wide "@type" disallows valid sub-properties 31 | // (when excess property checking is on) 32 | const _6: Thing = { 33 | '@type': 'Thing', 34 | name: 'a', 35 | // @ts-expect-error Thing too broad for additionalName 36 | additionalName: ['b', 'c', 'd'], 37 | }; 38 | -------------------------------------------------------------------------------- /packages/schema-dts/test/graph.ts: -------------------------------------------------------------------------------- 1 | import {Graph} from '../dist/schema'; 2 | 3 | // "@context" and "@graph" are both required 4 | // @ts-expect-error Missing @graph and @context 5 | const _1: Graph = {}; 6 | 7 | // @ts-expect-error Missing @context 8 | const _2: Graph = {'@graph': []}; 9 | 10 | // @ts-expect-error Missing @graph 11 | const _3: Graph = {'@context': 'https://schema.org'}; 12 | 13 | const _4: Graph = { 14 | '@context': 'https://schema.org', 15 | '@graph': [], 16 | }; 17 | 18 | // "@context" must be correct. 19 | const _5: Graph = { 20 | // @ts-expect-error Incorrect context 21 | '@context': 'https://google.com', 22 | '@graph': [], 23 | }; 24 | 25 | // "@graph" can have full objects, and types 26 | const _6: Graph = { 27 | '@context': 'https://schema.org', 28 | '@graph': [ 29 | {'@type': 'Thing'}, 30 | {'@type': 'Thing', '@id': 'X'}, 31 | {'@type': 'Person', knowsAbout: {'@id': 'X'}}, 32 | ], 33 | }; 34 | 35 | // "@graph" still type-checks 36 | const _7: Graph = { 37 | '@context': 'https://schema.org', 38 | '@graph': [ 39 | { 40 | '@type': 'Thing', 41 | // @ts-expect-error Unknown property 42 | g: 5, 43 | }, 44 | { 45 | // @ts-expect-error Invalid type 46 | '@type': 'Thingz', 47 | '@id': 'X', 48 | }, 49 | {'@type': 'Person', knowsAbout: {'@id': 'X'}}, 50 | ], 51 | }; 52 | -------------------------------------------------------------------------------- /packages/schema-dts/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "noEmit": true, 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/schema-dts/test/values.ts: -------------------------------------------------------------------------------- 1 | import {Thing} from '../dist/schema'; 2 | 3 | // Strings & Roles work 4 | const _1: Thing = { 5 | '@type': 'Person', 6 | knowsAbout: [ 7 | {'@id': 'A'}, 8 | 'B', 9 | {'@type': 'Role', knowsAbout: {'@id': 'A'}, roleName: 'abc'}, 10 | {'@type': 'Role', knowsAbout: 'B', roleName: 'bce'}, 11 | ], 12 | }; 13 | 14 | // Numbers work 15 | const _2: Thing = { 16 | '@type': 'Accommodation', 17 | numberOfBedrooms: 5, 18 | numberOfBathroomsTotal: '6', 19 | numberOfFullBathrooms: '555.3', 20 | }; 21 | 22 | // Numbers work in Roles 23 | const _3: Thing = { 24 | '@type': 'Accommodation', 25 | numberOfBedrooms: {'@type': 'Role', numberOfBedrooms: 5}, 26 | numberOfBathroomsTotal: {'@type': 'Role', numberOfBathroomsTotal: '6'}, 27 | numberOfFullBathrooms: {'@type': 'Role', numberOfFullBathrooms: '555.3'}, 28 | }; 29 | 30 | // Numbers work in strings 31 | const _4: Thing = { 32 | '@type': 'Accommodation', 33 | numberOfBedrooms: [5, '6', '555'], 34 | numberOfBathroomsTotal: ['6'], 35 | }; 36 | 37 | // Numbers must be valid 38 | const _5: Thing = { 39 | '@type': 'Accommodation', 40 | numberOfBedrooms: [ 41 | 5, 42 | // @ts-expect-error Invalid number 43 | '6abc', 44 | '555', 45 | ], 46 | // @ts-expect-error Invalid number in array 47 | numberOfBathroomsTotal: ['6def'], 48 | // @ts-expect-error Invalid number 49 | numberOfFullBathrooms: '55ggg5.3', 50 | }; 51 | 52 | // Roles must be valid 53 | const _6: Thing = { 54 | '@type': 'Person', 55 | knowsAbout: [ 56 | // @ts-expect-error Invalid role 57 | {'@type': 'Role', knowsAbourt: {'@id': 'A'}, roleName: 'abc'}, 58 | // @ts-expect-error Invalid role 59 | { 60 | '@type': 'Role', 61 | knowsAbout: {}, 62 | roleName: 'bce', 63 | }, 64 | ], 65 | }; 66 | -------------------------------------------------------------------------------- /packages/schema-dts/test/withactionconstraints.ts: -------------------------------------------------------------------------------- 1 | import {SearchAction, WebSite, WithActionConstraints} from '../dist/schema'; 2 | 3 | // @ts-expect-error Missing '@type' 4 | const _1: WithActionConstraints = {}; 5 | 6 | const _2: SearchAction = { 7 | '@type': 'SearchAction', 8 | // @ts-expect-error 'query-input' is not defined 9 | 'query-input': 'required name=search_term_string', 10 | }; 11 | 12 | const _3: WithActionConstraints = { 13 | '@type': 'SearchAction', 14 | 'query-input': 'required name=search_term_string', 15 | }; 16 | 17 | const _4: WithActionConstraints = { 18 | '@type': 'SearchAction', 19 | // @ts-expect-error 'query-inputs' is not defined 20 | 'query-inputs': 'required name=search_term_string', 21 | }; 22 | 23 | const _5: WebSite = { 24 | '@type': 'WebSite', 25 | potentialAction: { 26 | '@type': 'SearchAction', 27 | 'query-input': 'required name=search_term_string', 28 | } as WithActionConstraints, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/schema-dts/test/withcontext.ts: -------------------------------------------------------------------------------- 1 | import {Thing, WithContext} from '../dist/schema'; 2 | 3 | // "@context" and "@type" are both required 4 | // @ts-expect-error Missing '@type' and '@contet.' 5 | const _1: WithContext = {}; 6 | 7 | // @ts-expect-error Missing '@context' 8 | const _2: WithContext = {'@type': 'Thing'}; 9 | 10 | // @ts-expect-error Missing '@type' 11 | const _3: WithContext = {'@context': 'https://schema.org'}; 12 | 13 | const _4: WithContext = { 14 | '@context': 'https://schema.org', 15 | '@type': 'Thing', 16 | }; 17 | 18 | // "@context" must be correct. 19 | const _5: WithContext = { 20 | // @ts-expect-error Must be schema.org 21 | '@context': 'https://google.com', 22 | '@type': 'Thing', 23 | }; 24 | -------------------------------------------------------------------------------- /packages/schema-dts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "declaration": true, 5 | "outDir": "dist" 6 | }, 7 | "files": ["lib/schema.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "es2015", 5 | "module": "ES2020", 6 | "esModuleInterop": true, 7 | "moduleResolution": "node", 8 | "declaration": true, 9 | "declarationMap": true, 10 | "sourceMap": true, 11 | "composite": true, 12 | "lib": ["ES2015", "ES2019.Array"] 13 | } 14 | } 15 | --------------------------------------------------------------------------------