From f289bb8c9b001f844d61650b744f74a808a31b68 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 29 Sep 2021 18:55:41 -0700 Subject: [PATCH] Test that typedoc builds with no warnings --- .eslintrc.json | 3 +- .gitignore | 2 + js-api-doc/importer.d.ts | 38 ++------ js-api-doc/index.d.ts | 24 ++++- js-api-doc/legacy/function.d.ts | 13 +-- js-api-doc/legacy/importer.d.ts | 10 +-- js-api-doc/legacy/options.d.ts | 26 +++--- js-api-doc/options.d.ts | 15 ++-- js-api-doc/util/promise_or.d.ts | 7 ++ package-lock.json | 148 ++++++++++++++++++++++++++++++- package.json | 6 +- spec/js-api/importer.d.ts | 68 ++++---------- spec/js-api/index.d.ts | 24 ++++- spec/js-api/legacy/function.d.ts | 13 +-- spec/js-api/legacy/importer.d.ts | 10 +-- spec/js-api/legacy/options.d.ts | 26 +++--- spec/js-api/options.d.ts | 19 ++-- spec/js-api/util/promise_or.d.ts | 7 ++ 18 files changed, 302 insertions(+), 157 deletions(-) create mode 100644 js-api-doc/util/promise_or.d.ts create mode 100644 spec/js-api/util/promise_or.d.ts diff --git a/.eslintrc.json b/.eslintrc.json index f95bb333..4ed5d749 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,4 @@ { - "extends": "./node_modules/gts/" + "extends": "./node_modules/gts/", + "ignorePatterns": ["/docs/**"] } diff --git a/.gitignore b/.gitignore index 26031555..0af35f50 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,5 @@ typings/ .dynamodb/ # End of https://www.gitignore.io/api/node + +/docs diff --git a/js-api-doc/importer.d.ts b/js-api-doc/importer.d.ts index d0a6c532..fd3f6312 100644 --- a/js-api-doc/importer.d.ts +++ b/js-api-doc/importer.d.ts @@ -1,21 +1,15 @@ import {URL} from 'url'; import {Syntax} from './options'; +import {PromiseOr} from './util/promise_or'; -interface SyncFileImporter { +export interface FileImporter< + sync extends 'sync' | 'async' = 'sync' | 'async' +> { findFileUrl( url: string, options: {fromImport: boolean} - ): FileImporterResult | null; - - canonicalize?: never; -} - -interface AsyncFileImporter { - findFileUrl( - url: string, - options: {fromImport: boolean} - ): Promise | FileImporterResult | null; + ): PromiseOr; canonicalize?: never; } @@ -26,21 +20,13 @@ export interface FileImporterResult { sourceMapUrl?: URL; } -interface SyncImporter { - canonicalize(url: string, options: {fromImport: boolean}): URL | null; - load(canonicalUrl: URL): ImporterResult | null; - findFileUrl?: never; -} - -interface AsyncImporter { +export interface Importer { canonicalize( url: string, options: {fromImport: boolean} - ): Promise | URL | null; + ): PromiseOr; - load( - canonicalUrl: URL - ): Promise | ImporterResult | null; + load(canonicalUrl: URL): PromiseOr; findFileUrl?: never; } @@ -52,11 +38,3 @@ export interface ImporterResult { sourceMapUrl?: URL; } - -export type FileImporter = sync extends 'async' - ? AsyncFileImporter - : SyncFileImporter; - -export type Importer = sync extends 'async' - ? AsyncImporter - : SyncImporter; diff --git a/js-api-doc/index.d.ts b/js-api-doc/index.d.ts index 730eacae..9c121ca6 100644 --- a/js-api-doc/index.d.ts +++ b/js-api-doc/index.d.ts @@ -24,6 +24,7 @@ export { StringOptions, Syntax, } from './options'; +export {PromiseOr} from './util/promise_or'; export { ListSeparator, SassArgumentList, @@ -42,9 +43,26 @@ export { // Legacy APIs export {LegacyException} from './legacy/exception'; -export {LegacyFunction, LegacyValue, types} from './legacy/function'; -export {LegacyImporter} from './legacy/importer'; -export {LegacyOptions} from './legacy/options'; +export { + LegacyAsyncFunction, + LegacySyncFunction, + LegacyFunction, + LegacyValue, + types, +} from './legacy/function'; +export { + ImporterThis, + LegacyAsyncImporter, + LegacySyncImporter, + LegacyImporter, +} from './legacy/importer'; +export { + LegacySharedOptions, + LegacyFileOptions, + LegacyStringOptions, + LegacyOptions, +} from './legacy/options'; +export {PluginThis} from './legacy/plugin_this'; export {LegacyResult, render, renderSync} from './legacy/render'; export const info: string; diff --git a/js-api-doc/legacy/function.d.ts b/js-api-doc/legacy/function.d.ts index cddaddbd..66d9f3aa 100644 --- a/js-api-doc/legacy/function.d.ts +++ b/js-api-doc/legacy/function.d.ts @@ -1,15 +1,18 @@ import {PluginThis} from './plugin_this'; -type _SyncFunction = (this: PluginThis, ...args: LegacyValue[]) => LegacyValue; +export type LegacySyncFunction = ( + this: PluginThis, + ...args: LegacyValue[] +) => LegacyValue; -type _AsyncFunction = ( +export type LegacyAsyncFunction = ( this: PluginThis, ...args: [...LegacyValue[], (type: LegacyValue) => void] ) => void; -export type LegacyFunction = - | _SyncFunction - | (sync extends 'async' ? _AsyncFunction : never); +export type LegacyFunction = sync extends 'async' + ? LegacySyncFunction | LegacyAsyncFunction + : LegacySyncFunction; export type LegacyValue = | types.Null diff --git a/js-api-doc/legacy/importer.d.ts b/js-api-doc/legacy/importer.d.ts index 17c9f13f..0a0e6f93 100644 --- a/js-api-doc/legacy/importer.d.ts +++ b/js-api-doc/legacy/importer.d.ts @@ -4,19 +4,19 @@ interface ImporterThis extends PluginThis { fromImport: boolean; } -type _SyncImporter = ( +type LegacySyncImporter = ( this: ImporterThis, url: string, prev: string ) => {file: string} | {contents: string}; -type _AsyncImporter = ( +type LegacyAsyncImporter = ( this: ImporterThis, url: string, prev: string, done: (data: {file: string} | {contents: string} | Error) => void ) => void; -export type LegacyImporter = - | _SyncImporter - | (sync extends 'async' ? _AsyncImporter : never); +export type LegacyImporter = sync extends 'async' + ? LegacySyncImporter | LegacyAsyncImporter + : LegacySyncImporter; diff --git a/js-api-doc/legacy/options.d.ts b/js-api-doc/legacy/options.d.ts index a8cdb93e..b6ed617e 100644 --- a/js-api-doc/legacy/options.d.ts +++ b/js-api-doc/legacy/options.d.ts @@ -7,7 +7,7 @@ import {LegacyFunction} from './function'; * This is only exported so that it can be modified by proposals for new * features. It should not be referred to by user code. */ -export interface _Options { +export interface LegacySharedOptions { includePaths?: string[]; indentedSyntax?: boolean; indentType?: 'space' | 'tab'; @@ -32,13 +32,17 @@ export interface _Options { logger?: Logger; } -export type LegacyOptions = _Options & - ( - | { - file: string; - } - | { - data: string; - file?: string; - } - ); +export interface LegacyFileOptions + extends LegacySharedOptions { + file: string; +} + +export interface LegacyStringOptions + extends LegacySharedOptions { + data: string; + file?: string; +} + +export type LegacyOptions = + | LegacyFileOptions + | LegacySharedOptions; diff --git a/js-api-doc/options.d.ts b/js-api-doc/options.d.ts index bc711bfe..35df9605 100644 --- a/js-api-doc/options.d.ts +++ b/js-api-doc/options.d.ts @@ -3,18 +3,15 @@ import {URL} from 'url'; import {FileImporter, Importer} from './importer'; import {Logger} from './logger'; import {Value} from './value'; +import {PromiseOr} from './util/promise_or'; export type Syntax = 'scss' | 'indented' | 'css'; export type OutputStyle = 'expanded' | 'compressed'; -export type CustomFunction = sync extends 'sync' - ? (args: Value[]) => Value - : (args: Value[]) => Value | Promise; - -type _Importer = - | Importer - | FileImporter; +export type CustomFunction = ( + args: Value[] +) => PromiseOr; export interface Options { alertAscii?: boolean; @@ -23,7 +20,7 @@ export interface Options { functions?: Record>; - importers?: _Importer[]; + importers?: (Importer | FileImporter)[]; loadPaths?: string[]; @@ -45,7 +42,7 @@ export type StringOptions = Options & { url?: URL; } | { - importer: _Importer; + importer: Importer | FileImporter; url: URL; } ); diff --git a/js-api-doc/util/promise_or.d.ts b/js-api-doc/util/promise_or.d.ts new file mode 100644 index 00000000..1c473f54 --- /dev/null +++ b/js-api-doc/util/promise_or.d.ts @@ -0,0 +1,7 @@ +/** + * A utility type for choosing between synchronous and asynchronous return + * values. + */ +export type PromiseOr = sync extends 'sync' + ? T + : T | Promise; diff --git a/package-lock.json b/package-lock.json index 6945bdaa..688fa3aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,8 @@ "prettier": "^2.4.1", "source-map-js": "^0.6.2", "strip-comments": "^2.0.1", - "ts-node": "^10.2.1" + "ts-node": "^10.2.1", + "typedoc": "^0.22.4" }, "devDependencies": { "@types/node": "^14.11.2", @@ -2673,6 +2674,11 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" + }, "node_modules/jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -2852,6 +2858,11 @@ "node": ">=10" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -3266,6 +3277,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/onigasm": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", + "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", + "dependencies": { + "lru-cache": "^5.1.1" + } + }, + "node_modules/onigasm/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/onigasm/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4036,6 +4068,16 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.11.tgz", + "integrity": "sha512-tjruNTLFhU0hruCPoJP0y+B9LKOmcqUhTpxn7pcJB3fa+04gFChuEmxmrUfOJ7ZO6Jd+HwMnDHgY3lv3Tqonuw==", + "dependencies": { + "jsonc-parser": "^3.0.0", + "onigasm": "^2.2.5", + "vscode-textmate": "5.2.0" + } + }, "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -4507,6 +4549,38 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typedoc": { + "version": "0.22.4", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.4.tgz", + "integrity": "sha512-M/a8NnPxq3/iZNNVjzFCK5gu4m//HTJIPbSS0JQVbkHJPP9wyepR12agylWTSqeVZe0xsbidVtO26+PP7iD/jw==", + "dependencies": { + "glob": "^7.1.7", + "lunr": "^2.3.9", + "marked": "^3.0.4", + "minimatch": "^3.0.4", + "shiki": "^0.9.11" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 12.10.0" + }, + "peerDependencies": { + "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x" + } + }, + "node_modules/typedoc/node_modules/marked": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.4.tgz", + "integrity": "sha512-jBo8AOayNaEcvBhNobg6/BLhdsK3NvnKWJg33MAAPbvTWiG4QBn9gpW1+7RssrKu4K1dKlN+0goVQwV41xEfOA==", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/typescript": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", @@ -4622,6 +4696,11 @@ "extsprintf": "^1.2.0" } }, + "node_modules/vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6714,6 +6793,11 @@ "minimist": "^1.2.5" } }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6866,6 +6950,11 @@ "yallist": "^4.0.0" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -7177,6 +7266,29 @@ "mimic-fn": "^2.1.0" } }, + "onigasm": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", + "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", + "requires": { + "lru-cache": "^5.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7734,6 +7846,16 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shiki": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.11.tgz", + "integrity": "sha512-tjruNTLFhU0hruCPoJP0y+B9LKOmcqUhTpxn7pcJB3fa+04gFChuEmxmrUfOJ7ZO6Jd+HwMnDHgY3lv3Tqonuw==", + "requires": { + "jsonc-parser": "^3.0.0", + "onigasm": "^2.2.5", + "vscode-textmate": "5.2.0" + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -8085,6 +8207,25 @@ "is-typedarray": "^1.0.0" } }, + "typedoc": { + "version": "0.22.4", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.4.tgz", + "integrity": "sha512-M/a8NnPxq3/iZNNVjzFCK5gu4m//HTJIPbSS0JQVbkHJPP9wyepR12agylWTSqeVZe0xsbidVtO26+PP7iD/jw==", + "requires": { + "glob": "^7.1.7", + "lunr": "^2.3.9", + "marked": "^3.0.4", + "minimatch": "^3.0.4", + "shiki": "^0.9.11" + }, + "dependencies": { + "marked": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.4.tgz", + "integrity": "sha512-jBo8AOayNaEcvBhNobg6/BLhdsK3NvnKWJg33MAAPbvTWiG4QBn9gpW1+7RssrKu4K1dKlN+0goVQwV41xEfOA==" + } + } + }, "typescript": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", @@ -8174,6 +8315,11 @@ "extsprintf": "^1.2.0" } }, + "vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==" + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 396b4342..fa865f6b 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,9 @@ "toc-check": "npx ts-node test/toc-check.ts", "update-toc": "npx ts-node tool/update-toc.ts", "js-api-doc-check": "npx ts-node test/js-api-doc-check.ts", + "typedoc": "npx typedoc --treatWarningsAsErrors js-api-doc/index.d.ts", "fix": "gts fix", - "test": "gts lint && tsc --noEmit && npm run toc-check && npm run link-check && npm run js-api-doc-check" + "test": "gts lint && tsc --noEmit && npm run toc-check && npm run link-check && npm run js-api-doc-check && npm run typedoc" }, "dependencies": { "@types/diff": "^5.0.1", @@ -30,7 +31,8 @@ "prettier": "^2.4.1", "source-map-js": "^0.6.2", "strip-comments": "^2.0.1", - "ts-node": "^10.2.1" + "ts-node": "^10.2.1", + "typedoc": "^0.22.4" }, "devDependencies": { "@types/node": "^14.11.2", diff --git a/spec/js-api/importer.d.ts b/spec/js-api/importer.d.ts index 3254234d..7b045990 100644 --- a/spec/js-api/importer.d.ts +++ b/spec/js-api/importer.d.ts @@ -1,6 +1,7 @@ import {URL} from 'url'; import {Syntax} from './options'; +import {PromiseOr} from './util/promise_or'; /** * This interface represents an [importer]. When the importer is invoked with a @@ -12,7 +13,8 @@ import {Syntax} from './options'; * and `false` otherwise. * * - Let `url` be the result of calling `findFileUrl` with `url` and - * `fromImport`. + * `fromImport`. If it returns a promise, wait for it to complete and use its + * value instead, or rethrow its error if it rejects. * * - If `url` is null, return null. * @@ -36,26 +38,13 @@ import {Syntax} from './options'; * * [resolving `url`]: ../spec/modules.md#resolving-a-file-url */ -interface SyncFileImporter { +export interface FileImporter< + sync extends 'sync' | 'async' = 'sync' | 'async' +> { findFileUrl( url: string, options: {fromImport: boolean} - ): FileImporterResult | null; - - canonicalize?: never; -} - -/** - * This interface represents an [importer]. It has the same behavior as - * `SyncFileImporter`, except that if `findFileUrl` returns a `Promise` it waits - * for it to complete and uses its value as the return value. If a `Promise` - * emits an error, it rethrows that error. - */ -interface AsyncFileImporter { - findFileUrl( - url: string, - options: {fromImport: boolean} - ): Promise | FileImporterResult | null; + ): PromiseOr; canonicalize?: never; } @@ -93,11 +82,14 @@ export interface FileImporterResult { * and `false` otherwise. * * - Let `url` be the result of calling `canonicalize` with `url` and - * `fromImport`. + * `fromImport`. If it returns a promise, wait for it to complete and use its + * value instead, or rethrow its error if it rejects. * * - If `url` is null, return null. * - * - Let `result` be the result of calling `load` with `url`. + * - Let `result` be the result of calling `load` with `url`. If it returns a + * promise, wait for it to complete and use its value instead, or rethrow its + * error if it rejects. * * - If `result` is null, return null. * @@ -111,27 +103,13 @@ export interface FileImporterResult { * * [resolving `url`]: ../spec/modules.md#resolving-a-file-url */ -interface SyncImporter { - canonicalize(url: string, options: {fromImport: boolean}): URL | null; - load(canonicalUrl: URL): ImporterResult | null; - findFileUrl?: never; -} - -/** - * This interface represents an [importer]. It has the same behavior as - * `SyncImporter`, except that if `canonicalize` or `load` return a `Promise` it - * waits for it to complete and uses its value as the return value. If a - * `Promise` emits an error, it rethrows that error. - */ -interface AsyncImporter { +export interface Importer { canonicalize( url: string, options: {fromImport: boolean} - ): Promise | URL | null; + ): PromiseOr; - load( - canonicalUrl: URL - ): Promise | ImporterResult | null; + load(canonicalUrl: URL): PromiseOr; findFileUrl?: never; } @@ -152,19 +130,3 @@ export interface ImporterResult { */ sourceMapUrl?: URL; } - -/** - * > This type is exported so that TypeScript users can explicitly write a class - * > that `implements FileImporter`. - */ -export type FileImporter = sync extends 'async' - ? AsyncFileImporter - : SyncFileImporter; - -/** - * > This type is exported so that TypeScript users can explicitly write a class - * > that `implements Importer`. - */ -export type Importer = sync extends 'async' - ? AsyncImporter - : SyncImporter; diff --git a/spec/js-api/index.d.ts b/spec/js-api/index.d.ts index 2473aa20..2cec412e 100644 --- a/spec/js-api/index.d.ts +++ b/spec/js-api/index.d.ts @@ -52,6 +52,7 @@ export { StringOptions, Syntax, } from './options'; +export {PromiseOr} from './util/promise_or'; export { ListSeparator, SassArgumentList, @@ -70,9 +71,26 @@ export { // Legacy APIs export {LegacyException} from './legacy/exception'; -export {LegacyFunction, LegacyValue, types} from './legacy/function'; -export {LegacyImporter} from './legacy/importer'; -export {LegacyOptions} from './legacy/options'; +export { + LegacyAsyncFunction, + LegacySyncFunction, + LegacyFunction, + LegacyValue, + types, +} from './legacy/function'; +export { + ImporterThis, + LegacyAsyncImporter, + LegacySyncImporter, + LegacyImporter, +} from './legacy/importer'; +export { + LegacySharedOptions, + LegacyFileOptions, + LegacyStringOptions, + LegacyOptions, +} from './legacy/options'; +export {PluginThis} from './legacy/plugin_this'; export {LegacyResult, render, renderSync} from './legacy/render'; /** diff --git a/spec/js-api/legacy/function.d.ts b/spec/js-api/legacy/function.d.ts index cddaddbd..66d9f3aa 100644 --- a/spec/js-api/legacy/function.d.ts +++ b/spec/js-api/legacy/function.d.ts @@ -1,15 +1,18 @@ import {PluginThis} from './plugin_this'; -type _SyncFunction = (this: PluginThis, ...args: LegacyValue[]) => LegacyValue; +export type LegacySyncFunction = ( + this: PluginThis, + ...args: LegacyValue[] +) => LegacyValue; -type _AsyncFunction = ( +export type LegacyAsyncFunction = ( this: PluginThis, ...args: [...LegacyValue[], (type: LegacyValue) => void] ) => void; -export type LegacyFunction = - | _SyncFunction - | (sync extends 'async' ? _AsyncFunction : never); +export type LegacyFunction = sync extends 'async' + ? LegacySyncFunction | LegacyAsyncFunction + : LegacySyncFunction; export type LegacyValue = | types.Null diff --git a/spec/js-api/legacy/importer.d.ts b/spec/js-api/legacy/importer.d.ts index 5514b03b..d0ecfe38 100644 --- a/spec/js-api/legacy/importer.d.ts +++ b/spec/js-api/legacy/importer.d.ts @@ -15,19 +15,19 @@ interface ImporterThis extends PluginThis { fromImport: boolean; } -type _SyncImporter = ( +type LegacySyncImporter = ( this: ImporterThis, url: string, prev: string ) => {file: string} | {contents: string}; -type _AsyncImporter = ( +type LegacyAsyncImporter = ( this: ImporterThis, url: string, prev: string, done: (data: {file: string} | {contents: string} | Error) => void ) => void; -export type LegacyImporter = - | _SyncImporter - | (sync extends 'async' ? _AsyncImporter : never); +export type LegacyImporter = sync extends 'async' + ? LegacySyncImporter | LegacyAsyncImporter + : LegacySyncImporter; diff --git a/spec/js-api/legacy/options.d.ts b/spec/js-api/legacy/options.d.ts index 45be4102..2b59befc 100644 --- a/spec/js-api/legacy/options.d.ts +++ b/spec/js-api/legacy/options.d.ts @@ -9,7 +9,7 @@ import {LegacyFunction} from './function'; * This is only exported so that it can be modified by proposals for new * features. It should not be referred to by user code. */ -export interface _Options { +export interface LegacySharedOptions { includePaths?: string[]; indentedSyntax?: boolean; indentType?: 'space' | 'tab'; @@ -66,13 +66,17 @@ export interface _Options { logger?: Logger; } -export type LegacyOptions = _Options & - ( - | { - file: string; - } - | { - data: string; - file?: string; - } - ); +export interface LegacyFileOptions + extends LegacySharedOptions { + file: string; +} + +export interface LegacyStringOptions + extends LegacySharedOptions { + data: string; + file?: string; +} + +export type LegacyOptions = + | LegacyFileOptions + | LegacySharedOptions; diff --git a/spec/js-api/options.d.ts b/spec/js-api/options.d.ts index 9f059c0b..46e8200f 100644 --- a/spec/js-api/options.d.ts +++ b/spec/js-api/options.d.ts @@ -3,6 +3,7 @@ import {URL} from 'url'; import {FileImporter, Importer} from './importer'; import {Logger} from './logger'; import {Value} from './value'; +import {PromiseOr} from './util/promise_or'; /** The types of input syntax that the compiler can parse. */ export type Syntax = 'scss' | 'indented' | 'css'; @@ -17,17 +18,9 @@ export type Syntax = 'scss' | 'indented' | 'css'; export type OutputStyle = 'expanded' | 'compressed'; /** A custom function that can be called from Sass stylesheets. */ -export type CustomFunction = sync extends 'sync' - ? (args: Value[]) => Value - : (args: Value[]) => Value | Promise; - -/** - * > This type allows options to refer to tersely refer to everything that - * > represents an importer. - */ -type _Importer = - | Importer - | FileImporter; +export type CustomFunction = ( + args: Value[] +) => PromiseOr; /** * All of the options for a Sass compilation that are shared by compiling from a @@ -64,7 +57,7 @@ export interface Options { functions?: Record>; /** The list of of custom importers to use to resolve file loads. */ - importers?: _Importer[]; + importers?: (Importer | FileImporter)[]; /** If set, the compiler must use these paths to resolve imports. */ loadPaths?: string[]; @@ -132,7 +125,7 @@ export type StringOptions = Options & { } | { /** The importer to use to resolve relative imports in the entrypoint. */ - importer: _Importer; + importer: Importer | FileImporter; /** The canonical URL of the entrypoint. */ url: URL; } diff --git a/spec/js-api/util/promise_or.d.ts b/spec/js-api/util/promise_or.d.ts new file mode 100644 index 00000000..1c473f54 --- /dev/null +++ b/spec/js-api/util/promise_or.d.ts @@ -0,0 +1,7 @@ +/** + * A utility type for choosing between synchronous and asynchronous return + * values. + */ +export type PromiseOr = sync extends 'sync' + ? T + : T | Promise;