diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..df3ddcba602 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.json linguist-language=JSON-with-Comments \ No newline at end of file diff --git a/.gitignore b/.gitignore index b4fc4c14c08..93f49bb5bb0 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,13 @@ typings/ # NPM Lockfiles package-lock.json + +# temp folder used by api-extractor +temp +packages-exp/**/temp + +# temp markdowns generated for individual SDKs +packages-exp/**/docs + +# files generated by api-extractor that should not be tracked +tsdoc-metadata.json \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index fae3be0b273..1a4875b99aa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ // Exclude installed dependencies from searches too "**/node_modules": true }, - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "files.associations": { "*.json": "jsonc" } } diff --git a/common/api-review/app-exp.api.md b/common/api-review/app-exp.api.md new file mode 100644 index 00000000000..3989076e0aa --- /dev/null +++ b/common/api-review/app-exp.api.md @@ -0,0 +1,44 @@ +## API Report File for "@firebase/app-exp" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { FirebaseApp } from '@firebase/app-types-exp'; +import { FirebaseAppConfig } from '@firebase/app-types-exp'; +import { FirebaseOptions } from '@firebase/app-types-exp'; +import { LogCallback } from '@firebase/logger'; +import { LogLevel } from '@firebase/logger'; +import { LogOptions } from '@firebase/logger'; + +// @public +export function deleteApp(app: FirebaseApp): Promise; + +// @public +export function getApp(name?: string): FirebaseApp; + +// @public +export function getApps(): FirebaseApp[]; + +// @public +export function initializeApp(options: FirebaseOptions, name?: string): FirebaseApp; + +// @public +export function initializeApp(options: FirebaseOptions, config?: FirebaseAppConfig): FirebaseApp; + +export { LogLevel } + +// @public +export function onLog(logCallback: LogCallback | null, options?: LogOptions): void; + +// @public +export function registerVersion(libraryKeyOrName: string, version: string, variant?: string): void; + +// @public +export const SDK_VERSION: string; + +// @public +export function setLogLevel(logLevel: LogLevel): void; + + +``` diff --git a/common/api-review/app-types-exp.api.md b/common/api-review/app-types-exp.api.md new file mode 100644 index 00000000000..5da58a3a2f3 --- /dev/null +++ b/common/api-review/app-types-exp.api.md @@ -0,0 +1,65 @@ +## API Report File for "@firebase/app-types-exp" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ComponentContainer } from '@firebase/component'; + +// @public +export interface FirebaseApp { + automaticDataCollectionEnabled: boolean; + + readonly name: string; + + readonly options: FirebaseOptions; +} + +// @public (undocumented) +export interface FirebaseAppConfig { + // (undocumented) + automaticDataCollectionEnabled?: boolean; + // (undocumented) + name?: string; +} + +// @internal (undocumented) +export interface _FirebaseAppInternal extends FirebaseApp { + // (undocumented) + checkDestroyed(): void; + // (undocumented) + container: ComponentContainer; + // (undocumented) + isDeleted: boolean; +} + +// @public (undocumented) +export interface FirebaseOptions { + // (undocumented) + apiKey?: string; + // (undocumented) + appId?: string; + // (undocumented) + authDomain?: string; + // (undocumented) + databaseURL?: string; + // (undocumented) + measurementId?: string; + // (undocumented) + messagingSenderId?: string; + // (undocumented) + projectId?: string; + // (undocumented) + storageBucket?: string; +} + +// @public (undocumented) +export interface PlatformLoggerService { + // (undocumented) + getPlatformInfoString(): string; +} + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/config/api-extractor.json b/config/api-extractor.json new file mode 100644 index 00000000000..078b4b0b510 --- /dev/null +++ b/config/api-extractor.json @@ -0,0 +1,370 @@ +/** + * Config file for API Extractor. For more info, please visit: https://api-extractor.com + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for + * standard settings to be shared across multiple projects. + * + * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains + * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be + * resolved using NodeJS require(). + * + * SUPPORTED TOKENS: none + * DEFAULT VALUE: "" + */ + // "extends": "./shared/api-extractor-base.json" + // "extends": "my-package/include/api-extractor-base.json" + + /** + * Determines the "" token that can be used with other config file settings. The project folder + * typically contains the tsconfig.json and package.json config files, but the path is user-defined. + * + * The path is resolved relative to the folder of the config file that contains the setting. + * + * The default value for "projectFolder" is the token "", which means the folder is determined by traversing + * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder + * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error + * will be reported. + * + * SUPPORTED TOKENS: + * DEFAULT VALUE: "" + */ + // "projectFolder": "..", + + /** + * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor + * analyzes the symbols exported by this module. + * + * The file extension must be ".d.ts" and not ".ts". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + */ + // Project should set this value to its entry point d.ts file. + // "mainEntryPointFilePath": "/lib/index.d.ts", + + /** + * A list of NPM package names whose exports should be treated as part of this package. + * + * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", + * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part + * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly + * imports library2. To avoid this, we can specify: + * + * "bundledPackages": [ "library2" ], + * + * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been + * local files for library1. + */ + "bundledPackages": [ ], + + /** + * Determines how the TypeScript compiler engine will be invoked by API Extractor. + */ + "compiler": { + /** + * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * Note: This setting will be ignored if "overrideTsconfig" is used. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/tsconfig.json" + */ + // "tsconfigFilePath": "/tsconfig.json", + + /** + * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. + * The object must conform to the TypeScript tsconfig schema: + * + * http://json.schemastore.org/tsconfig + * + * If omitted, then the tsconfig.json file will be read from the "projectFolder". + * + * DEFAULT VALUE: no overrideTsconfig section + */ + // "overrideTsconfig": { + // . . . + // } + + /** + * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended + * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when + * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses + * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. + * + * DEFAULT VALUE: false + */ + // "skipLibCheck": true, + }, + + /** + * Configures how the API report file (*.api.md) will be generated. + */ + "apiReport": { + /** + * (REQUIRED) Whether to generate an API report. + */ + "enabled": true, + + /** + * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce + * a full file path. + * + * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". + * + * SUPPORTED TOKENS: , + * DEFAULT VALUE: ".api.md" + */ + // "reportFileName": ".api.md", + + /** + * Specifies the folder where the API report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, + * e.g. for an API review. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/etc/" + */ + "reportFolder": "/../../common/api-review/", + + /** + * Specifies the folder where the temporary report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * After the temporary file is written to disk, it is compared with the file in the "reportFolder". + * If they are different, a production build will fail. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/" + */ + // "reportTempFolder": "/temp/" + }, + + /** + * Configures how the doc model file (*.api.json) will be generated. + */ + "docModel": { + /** + * (REQUIRED) Whether to generate a doc model file. + */ + "enabled": true, + + /** + * The output path for the doc model file. The file extension should be ".api.json". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/.api.json" + */ + // "apiJsonFilePath": "/temp/.api.json" + }, + + /** + * Configures how the .d.ts rollup file will be generated. + */ + "dtsRollup": { + /** + * (REQUIRED) Whether to generate the .d.ts rollup file. + */ + "enabled": true, + + /** + * Specifies the output path for a .d.ts rollup file to be generated without any trimming. + * This file will include all declarations that are exported by the main entry point. + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/dist/.d.ts" + */ + // "untrimmedFilePath": "/dist/.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. + * This file will include only declarations that are marked as "@public" or "@beta". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "betaTrimmedFilePath": "/dist/-beta.d.ts", + + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. + * This file will include only declarations that are marked as "@public". + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "publicTrimmedFilePath": "/dist/-public.d.ts", + + /** + * When a declaration is trimmed, by default it will be replaced by a code comment such as + * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the + * declaration completely. + * + * DEFAULT VALUE: false + */ + // "omitTrimmingComments": true + }, + + /** + * Configures how the tsdoc-metadata.json file will be generated. + */ + "tsdocMetadata": { + /** + * Whether to generate the tsdoc-metadata.json file. + * + * DEFAULT VALUE: true + */ + // "enabled": true, + + /** + * Specifies where the TSDoc metadata file should be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", + * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup + * falls back to "tsdoc-metadata.json" in the package folder. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" + }, + + /** + * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files + * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. + * To use the OS's default newline kind, specify "os". + * + * DEFAULT VALUE: "crlf" + */ + // "newlineKind": "crlf", + + /** + * Configures how API Extractor reports error and warning messages produced during analysis. + * + * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. + */ + "messages": { + /** + * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing + * the input .d.ts files. + * + * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "compilerMessageReporting": { + /** + * Configures the default routing for messages that don't match an explicit rule in this table. + */ + "default": { + /** + * Specifies whether the message should be written to the the tool's output log. Note that + * the "addToApiReportFile" property may supersede this option. + * + * Possible values: "error", "warning", "none" + * + * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail + * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes + * the "--local" option), the warning is displayed but the build will not fail. + * + * DEFAULT VALUE: "warning" + */ + "logLevel": "warning", + + /** + * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), + * then the message will be written inside that file; otherwise, the message is instead logged according to + * the "logLevel" option. + * + * DEFAULT VALUE: false + */ + // "addToApiReportFile": false + }, + + // "TS2551": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by API Extractor during its analysis. + * + * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" + * + * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings + */ + "extractorMessageReporting": { + "default": { + "logLevel": "warning", + // "addToApiReportFile": false + }, + + // "ae-extra-release-tag": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by the TSDoc parser when analyzing code comments. + * + * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "tsdocMessageReporting": { + "default": { + "logLevel": "warning", + // "addToApiReportFile": false + } + + // "tsdoc-link-tag-unescaped-text": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + } + } + +} diff --git a/package.json b/package.json index 39ddb1bb69b..f4aa97cd66d 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,9 @@ "docgen": "yarn docgen:js; yarn docgen:node", "prettier": "prettier --config .prettierrc --write '**/*.{ts,js}'", "lint": "lerna run --scope @firebase/* --scope rxfire lint", - "size-report": "node scripts/report_binary_size.js" + "size-report": "node scripts/report_binary_size.js", + "api-report": "lerna run --scope @firebase/*-exp api-report", + "docgen:exp": "node scripts/exp/docgen.js" }, "repository": { "type": "git", @@ -125,7 +127,9 @@ "typescript": "3.8.3", "watch": "1.0.2", "webpack": "4.42.0", - "yargs": "15.3.1" + "yargs": "15.3.1", + "@microsoft/api-extractor": "7.7.8", + "@microsoft/api-documenter": "7.7.12" }, "husky": { "hooks": { diff --git a/packages-exp/app-exp/api-extractor.json b/packages-exp/app-exp/api-extractor.json new file mode 100644 index 00000000000..da5cd700796 --- /dev/null +++ b/packages-exp/app-exp/api-extractor.json @@ -0,0 +1,5 @@ +{ + "extends": "../../config/api-extractor.json", + // Point it to your entry point d.ts file. + "mainEntryPointFilePath": "/dist/esm5/packages-exp/app-exp/src/index.d.ts" +} \ No newline at end of file diff --git a/packages-exp/app-exp/package.json b/packages-exp/app-exp/package.json index 9ded28fda44..ba9cf1b9afd 100644 --- a/packages-exp/app-exp/package.json +++ b/packages-exp/app-exp/package.json @@ -20,7 +20,11 @@ "test:browser": "karma start --single-run", "test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha src/**/*.test.ts --opts ../../config/mocha.node.opts", "type-check": "tsc -p . --noEmit", - "prepare": "yarn build" + "prepare": "yarn build", + "api-report": "api-extractor run --local --verbose", + "predoc": "node ../../scripts/exp/remove_exp.js temp", + "doc": "api-documenter markdown --input temp --output docs", + "build:doc": "yarn build && yarn api-report && yarn doc" }, "dependencies": { "@firebase/app-types-exp": "0.800.0", diff --git a/packages-exp/app-exp/src/api.test.ts b/packages-exp/app-exp/src/api.test.ts index b0dac2e2543..2f91c258380 100644 --- a/packages-exp/app-exp/src/api.test.ts +++ b/packages-exp/app-exp/src/api.test.ts @@ -29,7 +29,7 @@ import { onLog } from './api'; import { DEFAULT_ENTRY_NAME } from './constants'; -import { FirebaseAppInternal } from '@firebase/app-types-exp'; +import { _FirebaseAppInternal } from '@firebase/app-types-exp'; import { clearComponents, components, @@ -109,7 +109,7 @@ describe('API tests', () => { registerComponent(comp1); registerComponent(comp2); - const app = initializeApp({}) as FirebaseAppInternal; + const app = initializeApp({}) as _FirebaseAppInternal; // -1 here to not count the FirebaseApp provider that's added during initializeApp expect(app.container.getProviders().length - 1).to.equal(components.size); }); @@ -160,10 +160,10 @@ describe('API tests', () => { describe('deleteApp', () => { it('marks an App as deleted', async () => { const app = initializeApp({}); - expect((app as FirebaseAppInternal).isDeleted).to.be.false; + expect((app as _FirebaseAppInternal).isDeleted).to.be.false; await deleteApp(app).catch(() => {}); - expect((app as FirebaseAppInternal).isDeleted).to.be.true; + expect((app as _FirebaseAppInternal).isDeleted).to.be.true; }); it('removes App from the cache', () => { diff --git a/packages-exp/app-exp/src/api.ts b/packages-exp/app-exp/src/api.ts index 716c1b2fed2..23ed3341a99 100644 --- a/packages-exp/app-exp/src/api.ts +++ b/packages-exp/app-exp/src/api.ts @@ -19,7 +19,7 @@ import { FirebaseApp, FirebaseOptions, FirebaseAppConfig, - FirebaseAppInternal + _FirebaseAppInternal } from '@firebase/app-types-exp'; import { DEFAULT_ENTRY_NAME, PLATFORM_LOG_STRING } from './constants'; import { ERROR_FACTORY, AppError } from './errors'; @@ -43,19 +43,21 @@ import { /** * The current SDK version. + * + * @public */ export const SDK_VERSION = version; /** - * Creates and initializes a Firebase {@link @firebase/app-types-exp#FirebaseApp app} instance. + * Creates and initializes a FirebaseApp instance. * * See * {@link * https://firebase.google.com/docs/web/setup#add_firebase_to_your_app - * Add Firebase to your app} and + * | Add Firebase to your app} and * {@link * https://firebase.google.com/docs/web/setup#multiple-projects - * Initialize multiple projects} for detailed documentation. + * | Initialize multiple projects} for detailed documentation. * * @example * ```javascript @@ -82,19 +84,29 @@ export const SDK_VERSION = version; * }, "otherApp"); * ``` * - * @param options Options to configure the app's services. - * @param name Optional name of the app to initialize. If no name + * @param options - Options to configure the app's services. + * @param name - Optional name of the app to initialize. If no name * is provided, the default is `"[DEFAULT]"`. * - * @return {!firebase.app.App} The initialized app. + * @returns The initialized app. + * + * @public */ export function initializeApp( options: FirebaseOptions, - config?: FirebaseAppConfig + name?: string ): FirebaseApp; +/** + * Creates and initializes a FirebaseApp instance. + * + * @param options - Options to configure the app's services. + * @param config - FirebaseApp Configuration + * + * @public + */ export function initializeApp( options: FirebaseOptions, - name?: string + config?: FirebaseAppConfig ): FirebaseApp; export function initializeApp( options: FirebaseOptions, @@ -135,7 +147,7 @@ export function initializeApp( } /** - * Retrieves a Firebase {@link @firebase/app-types-exp#FirebaseApp app} instance. + * Retrieves a FirebaseApp instance. * * When called with no arguments, the default app is returned. When an app name * is provided, the app corresponding to that name is returned. @@ -155,11 +167,13 @@ export function initializeApp( * const otherApp = getApp("otherApp"); * ``` * - * @param name Optional name of the app to return. If no name is + * @param name - Optional name of the app to return. If no name is * provided, the default is `"[DEFAULT]"`. * - * @return The app corresponding to the provided app name. + * @returns The app corresponding to the provided app name. * If no app name is provided, the default app is returned. + * + * @public */ export function getApp(name: string = DEFAULT_ENTRY_NAME): FirebaseApp { const app = apps.get(name); @@ -172,6 +186,7 @@ export function getApp(name: string = DEFAULT_ENTRY_NAME): FirebaseApp { /** * A (read-only) array of all initialized apps. + * @public */ export function getApps(): FirebaseApp[] { return Array.from(apps.values()); @@ -191,23 +206,27 @@ export function getApps(): FirebaseApp[] { * console.log("Error deleting app:", error); * }); * ``` + * + * @public */ export async function deleteApp(app: FirebaseApp): Promise { const name = app.name; if (apps.has(name)) { apps.delete(name); - await (app as FirebaseAppInternal).container + await (app as _FirebaseAppInternal).container .getProviders() .map(provider => provider.delete()); - (app as FirebaseAppInternal).isDeleted = true; + (app as _FirebaseAppInternal).isDeleted = true; } } /** * Registers a library's name and version for platform logging purposes. - * @param library Name of 1p or 3p library (e.g. firestore, angularfire) - * @param version Current version of that library. - * @param variant Bundle variant, e.g., node, rn, etc. + * @param library - Name of 1p or 3p library (e.g. firestore, angularfire) + * @param version - Current version of that library. + * @param variant - Bundle variant, e.g., node, rn, etc. + * + * @public */ export function registerVersion( libraryKeyOrName: string, @@ -253,8 +272,10 @@ export function registerVersion( /** * Sets log handler for all Firebase SDKs. - * @param logCallback An optional custom log handler that executes user code whenever + * @param logCallback - An optional custom log handler that executes user code whenever * the Firebase SDK makes a logging call. + * + * @public */ export function onLog( logCallback: LogCallback | null, @@ -274,6 +295,8 @@ export function onLog( * All of the log types above the current log level are captured (i.e. if * you set the log level to `info`, errors are logged, but `debug` and * `verbose` logs are not). + * + * @public */ export function setLogLevel(logLevel: LogLevel): void { setLogLevelImpl(logLevel); diff --git a/packages-exp/app-exp/src/firebaseApp.test.ts b/packages-exp/app-exp/src/firebaseApp.test.ts index 8cbb9323075..12e56b41ff7 100644 --- a/packages-exp/app-exp/src/firebaseApp.test.ts +++ b/packages-exp/app-exp/src/firebaseApp.test.ts @@ -19,7 +19,7 @@ import { expect } from 'chai'; import '../test/setup'; import { FirebaseAppImpl } from './firebaseApp'; import { ComponentContainer } from '@firebase/component'; -import { FirebaseAppInternal } from '@firebase/app-types-exp'; +import { _FirebaseAppInternal } from '@firebase/app-types-exp'; describe('FirebaseAppNext', () => { it('has various accessors', () => { @@ -71,7 +71,7 @@ describe('FirebaseAppNext', () => { ); expect(() => app.name).to.not.throw(); - ((app as unknown) as FirebaseAppInternal).isDeleted = true; + ((app as unknown) as _FirebaseAppInternal).isDeleted = true; expect(() => { app.name; diff --git a/packages-exp/app-exp/src/index.ts b/packages-exp/app-exp/src/index.ts index 3d0a47ad8f8..79b112bfed5 100644 --- a/packages-exp/app-exp/src/index.ts +++ b/packages-exp/app-exp/src/index.ts @@ -1,7 +1,7 @@ /** * Firebase App * - * @remark This package coordinates the communication between the different Firebase components + * @remarks This package coordinates the communication between the different Firebase components * @packageDocumentation */ diff --git a/packages-exp/app-exp/src/internal.test.ts b/packages-exp/app-exp/src/internal.test.ts index fcc8bc3ab9e..5787cf8fd3e 100644 --- a/packages-exp/app-exp/src/internal.test.ts +++ b/packages-exp/app-exp/src/internal.test.ts @@ -27,7 +27,7 @@ import { components, clearComponents } from './internal'; -import { FirebaseAppInternal } from '@firebase/app-types-exp'; +import { _FirebaseAppInternal } from '@firebase/app-types-exp'; declare module '@firebase/component' { interface NameServiceMapping { @@ -44,7 +44,7 @@ describe('Internal API tests', () => { describe('addComponent', () => { it('registers component with App', () => { - const app = initializeApp({}) as FirebaseAppInternal; + const app = initializeApp({}) as _FirebaseAppInternal; const testComp = createTestComponent('test'); addComponent(app, testComp); @@ -55,7 +55,7 @@ describe('Internal API tests', () => { }); it('does NOT throw registering duplicate components', () => { - const app = initializeApp({}) as FirebaseAppInternal; + const app = initializeApp({}) as _FirebaseAppInternal; const testComp = createTestComponent('test'); addComponent(app, testComp); @@ -69,7 +69,7 @@ describe('Internal API tests', () => { describe('addOrOverwriteComponent', () => { it('registers component with App', () => { - const app = initializeApp({}) as FirebaseAppInternal; + const app = initializeApp({}) as _FirebaseAppInternal; const testComp = createTestComponent('test'); addOrOverwriteComponent(app, testComp); @@ -80,7 +80,7 @@ describe('Internal API tests', () => { }); it('overwrites an existing component with the same name', () => { - const app = initializeApp({}) as FirebaseAppInternal; + const app = initializeApp({}) as _FirebaseAppInternal; const testComp1 = createTestComponent('test'); const testComp2 = createTestComponent('test'); @@ -99,8 +99,8 @@ describe('Internal API tests', () => { }); it('caches a component and registers it with all Apps', () => { - const app1 = initializeApp({}) as FirebaseAppInternal; - const app2 = initializeApp({}, 'app2') as FirebaseAppInternal; + const app1 = initializeApp({}) as _FirebaseAppInternal; + const app2 = initializeApp({}, 'app2') as _FirebaseAppInternal; const stub1 = stub(app1.container, 'addComponent').callThrough(); const stub2 = stub(app2.container, 'addComponent').callThrough(); diff --git a/packages-exp/app-exp/src/internal.ts b/packages-exp/app-exp/src/internal.ts index 7a7ff1cae99..3d7c4390b6b 100644 --- a/packages-exp/app-exp/src/internal.ts +++ b/packages-exp/app-exp/src/internal.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { FirebaseAppInternal, FirebaseApp } from '@firebase/app-types-exp'; +import { _FirebaseAppInternal, FirebaseApp } from '@firebase/app-types-exp'; import { Component, Provider, Name } from '@firebase/component'; import { logger } from './logger'; @@ -31,7 +31,7 @@ export const components = new Map>(); */ export function addComponent(app: FirebaseApp, component: Component): void { try { - (app as FirebaseAppInternal).container.addComponent(component); + (app as _FirebaseAppInternal).container.addComponent(component); } catch (e) { logger.debug( `Component ${component.name} failed to register with FirebaseApp ${app.name}`, @@ -44,7 +44,7 @@ export function addOrOverwriteComponent( app: FirebaseApp, component: Component ): void { - (app as FirebaseAppInternal).container.addOrOverwriteComponent(component); + (app as _FirebaseAppInternal).container.addOrOverwriteComponent(component); } /** @@ -66,7 +66,7 @@ export function registerComponent(component: Component): boolean { // add the component to existing app instances for (const app of apps.values()) { - addComponent(app as FirebaseAppInternal, component); + addComponent(app as _FirebaseAppInternal, component); } return true; @@ -76,7 +76,7 @@ export function getProvider( app: FirebaseApp, name: T ): Provider { - return (app as FirebaseAppInternal).container.getProvider(name); + return (app as _FirebaseAppInternal).container.getProvider(name); } /** diff --git a/packages-exp/app-types-exp/api-extractor.json b/packages-exp/app-types-exp/api-extractor.json new file mode 100644 index 00000000000..42f37a88c4b --- /dev/null +++ b/packages-exp/app-types-exp/api-extractor.json @@ -0,0 +1,5 @@ +{ + "extends": "../../config/api-extractor.json", + // Point it to your entry point d.ts file. + "mainEntryPointFilePath": "/index.d.ts" +} \ No newline at end of file diff --git a/packages-exp/app-types-exp/index.d.ts b/packages-exp/app-types-exp/index.d.ts index 6c794b835f6..59f6c6d00b9 100644 --- a/packages-exp/app-types-exp/index.d.ts +++ b/packages-exp/app-types-exp/index.d.ts @@ -22,8 +22,9 @@ import { ComponentContainer } from '@firebase/component'; * services. * * Do not call this constructor directly. Instead, use - * {@link firebase.initializeApp|`firebase.initializeApp()`} to create an app. + * {@link @firebase/app-exp#(initializeApp:1) | initializeApp()} to create an app. * + * @public */ export interface FirebaseApp { /** @@ -49,7 +50,7 @@ export interface FirebaseApp { /** * The (read-only) configuration options for this app. These are the original - * parameters given in {@link @firebase/app-exp#initializApp}. + * parameters given in {@link @firebase/app-exp#(initializeApp:1) | initializeApp()}. * * @example * ```javascript @@ -65,12 +66,18 @@ export interface FirebaseApp { automaticDataCollectionEnabled: boolean; } -export interface FirebaseAppInternal extends FirebaseApp { +/** + * @internal + */ +export interface _FirebaseAppInternal extends FirebaseApp { container: ComponentContainer; isDeleted: boolean; checkDestroyed(): void; } +/** + * @public + */ export interface FirebaseOptions { apiKey?: string; authDomain?: string; @@ -82,11 +89,17 @@ export interface FirebaseOptions { measurementId?: string; } +/** + * @public + */ export interface FirebaseAppConfig { name?: string; automaticDataCollectionEnabled?: boolean; } +/** + * @public + */ export interface PlatformLoggerService { getPlatformInfoString(): string; } diff --git a/packages-exp/app-types-exp/package.json b/packages-exp/app-types-exp/package.json index 6f36d98adcd..ea6348a0062 100644 --- a/packages-exp/app-types-exp/package.json +++ b/packages-exp/app-types-exp/package.json @@ -6,7 +6,11 @@ "author": "Firebase (https://firebase.google.com/)", "license": "Apache-2.0", "scripts": { - "test": "tsc" + "test": "tsc", + "api-report": "api-extractor run --local --verbose", + "predoc": "node ../../scripts/exp/remove_exp.js temp", + "doc": "api-documenter markdown --input temp --output docs", + "build:doc": "yarn api-report && yarn doc" }, "files": [ "index.d.ts", diff --git a/scripts/exp/docgen.js b/scripts/exp/docgen.js new file mode 100644 index 00000000000..af6cb23b1fc --- /dev/null +++ b/scripts/exp/docgen.js @@ -0,0 +1,77 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { spawn } = require('child-process-promise'); +const { mapWorkspaceToPackages } = require('../release/utils/workspace'); +const { projectRoot } = require('../utils'); +const { removeExpSuffix } = require('./remove-exp'); +const fs = require('fs'); +const glob = require('glob'); + +const tmpDir = `${projectRoot}/temp`; +// create *.api.json files +async function generateDocs() { + // TODO: change yarn command once exp packages become official + await spawn('yarn', ['build:exp'], { + stdio: 'inherit' + }); + + await spawn('yarn', ['api-report'], { + stdio: 'inherit' + }); + + if (!fs.existsSync(tmpDir)) { + fs.mkdirSync(tmpDir); + } + + // TODO: Throw error if path doesn't exist, once all packages add markdown support. + const apiJsonDirectories = ( + await mapWorkspaceToPackages([ + `${projectRoot}/packages/*`, + `${projectRoot}/packages-exp/*` + ]) + ) + .map(path => `${path}/temp`) + .filter(path => fs.existsSync(path)); + + for (const dir of apiJsonDirectories) { + const paths = await new Promise(resolve => + glob(`${dir}/*.api.json`, (err, paths) => { + if (err) throw err; + resolve(paths); + }) + ); + + if (paths.length === 0) { + throw Error(`*.api.json file is missing in ${dir}`); + } + + // there will be only 1 api.json file + const fileName = paths[0].split('/').pop(); + fs.copyFileSync(paths[0], `${tmpDir}/${fileName}`); + } + + // Generate docs without the -exp suffix + removeExpSuffix(tmpDir); + await spawn( + 'npx', + ['api-documenter', 'markdown', '--input', 'temp', '--output', 'docs-exp'], + { stdio: 'inherit' } + ); +} + +generateDocs(); diff --git a/scripts/exp/remove-exp.js b/scripts/exp/remove-exp.js new file mode 100644 index 00000000000..44f24429e8e --- /dev/null +++ b/scripts/exp/remove-exp.js @@ -0,0 +1,45 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Replace "-exp" with "" in all files within the directory + */ +const { argv } = require('yargs'); +const path = require('path'); +const { readdirSync, statSync, readFileSync, writeFileSync } = require('fs'); + +// can be used in command line +if (argv._[0]) { + const dir = path.resolve(argv._[0]); + removeExpSuffix(dir); +} + +function removeExpSuffix(dir) { + for (const file of readdirSync(dir)) { + const filePath = `${dir}/${file}`; + if (statSync(filePath).isFile()) { + const content = readFileSync(filePath, 'utf-8'); + + // replace -exp with empty string + const modified = content.replace(/-exp/g, ''); + + writeFileSync(filePath, modified, 'utf-8'); + } + } +} + +exports.removeExpSuffix = removeExpSuffix; diff --git a/scripts/release/utils/constants.js b/scripts/release/utils/constants.js deleted file mode 100644 index 82ad2a42b77..00000000000 --- a/scripts/release/utils/constants.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license - * Copyright 2018 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const { dirname, resolve } = require('path'); -exports.projectRoot = dirname(resolve(__dirname, '../../../package.json')); diff --git a/scripts/release/utils/git.js b/scripts/release/utils/git.js index 6e77953001f..b75d5266b59 100644 --- a/scripts/release/utils/git.js +++ b/scripts/release/utils/git.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2018 Google Inc. + * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ */ const simpleGit = require('simple-git/promise'); -const { projectRoot: root } = require('./constants'); +const { projectRoot: root } = require('../../utils'); const git = simpleGit(root); const { exec } = require('child-process-promise'); const ora = require('ora'); diff --git a/scripts/release/utils/lerna.js b/scripts/release/utils/lerna.js index 721a6fdebd3..af7dce2f68e 100644 --- a/scripts/release/utils/lerna.js +++ b/scripts/release/utils/lerna.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2018 Google Inc. + * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ const { exec } = require('child-process-promise'); const npmRunPath = require('npm-run-path'); -const { projectRoot: root } = require('./constants'); +const { projectRoot: root } = require('../../utils'); function getLernaUpdateJson() { let cache; diff --git a/scripts/release/utils/workspace.js b/scripts/release/utils/workspace.js index fd1214943cb..92574ca2c3f 100644 --- a/scripts/release/utils/workspace.js +++ b/scripts/release/utils/workspace.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2018 Google Inc. + * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ */ const glob = require('glob'); -const { projectRoot: root } = require('./constants'); +const { projectRoot: root } = require('../../utils'); const { workspaces: rawWorkspaces } = require(`${root}/package.json`); const workspaces = rawWorkspaces.map(workspace => `${root}/${workspace}`); const { DepGraph } = require('dependency-graph'); @@ -26,15 +26,6 @@ const { writeFile: _writeFile, existsSync } = require('fs'); const writeFile = promisify(_writeFile); const clone = require('clone'); -function filterObjectByKey(raw, filter) { - return Object.keys(raw) - .filter(filter) - .reduce((obj, key) => { - obj[key] = raw[key]; - return obj; - }, {}); -} - function mapWorkspaceToPackages(workspaces) { return Promise.all( workspaces.map( @@ -48,6 +39,7 @@ function mapWorkspaceToPackages(workspaces) { ) ).then(paths => paths.reduce((arr, val) => arr.concat(val), [])); } +exports.mapWorkspaceToPackages = mapWorkspaceToPackages; function mapPackagestoPkgJson(packagePaths) { return packagePaths diff --git a/scripts/report_binary_size.js b/scripts/report_binary_size.js index 8a1379ffb45..e4f217a1171 100644 --- a/scripts/report_binary_size.js +++ b/scripts/report_binary_size.js @@ -21,8 +21,6 @@ const { execSync } = require('child_process'); const https = require('https'); const terser = require('terser'); -const repoRoot = resolve(__dirname, '..'); - const runId = process.env.GITHUB_RUN_ID || 'local-run-id'; const METRICS_SERVICE_URL = process.env.METRICS_SERVICE_URL; @@ -70,9 +68,7 @@ function generateReportForNPMPackages() { ]; const packageInfo = JSON.parse( - execSync('npx lerna ls --json --scope @firebase/*', { - cwd: repoRoot - }).toString() + execSync('npx lerna ls --json --scope @firebase/*').toString() ); for (const package of packageInfo) { diff --git a/scripts/utils.js b/scripts/utils.js new file mode 100644 index 00000000000..15760c23677 --- /dev/null +++ b/scripts/utils.js @@ -0,0 +1,61 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { dirname, resolve } = require('path'); +const simpleGit = require('simple-git/promise'); +const { exec } = require('child-process-promise'); + +const projectRoot = dirname(resolve(__dirname, '../package.json')); +exports.projectRoot = projectRoot; + +async function getChangedFiles() { + console.log(projectRoot); + const git = simpleGit(projectRoot); + const diff = await git.diff(['--name-only', 'origin/master...HEAD']); + const changedFiles = diff.split('\n'); + + return changedFiles; +} +exports.getChangedFiles = getChangedFiles; + +async function getChangedPackages() { + const changedPackages = new Set(); + for (const filename of await getChangedFiles()) { + // Check for changed files inside package dirs. + const match = filename.match('^(packages(-exp)?/[a-zA-Z0-9-]+)/.*'); + if (match && match[1]) { + const changedPackage = require(resolve( + projectRoot, + match[1], + 'package.json' + )); + changedPackages.add(changedPackage.name); + } + } + return Array.from(changedPackages.values()); +} +exports.getChangedPackages = getChangedPackages; + +exports.getPackageInfo = async function( + { includePrivate } = { includePrivate: true } +) { + const packageInfo = JSON.parse( + (await exec(`npx lerna ls ${includePrivate ? '-la' : ''} --json`)).stdout + ); + + return packageInfo; +}; diff --git a/tools/gitHooks/api-report.js b/tools/gitHooks/api-report.js new file mode 100644 index 00000000000..f5f598fd5c4 --- /dev/null +++ b/tools/gitHooks/api-report.js @@ -0,0 +1,68 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * generate API reports in changed packages + */ + +const { + getChangedPackages, + getPackageInfo, + projectRoot +} = require('../../scripts/utils'); +const { execSync } = require('child_process'); +const ora = require('ora'); +const simpleGit = require('simple-git/promise'); + +const git = simpleGit(projectRoot); + +async function doApiReportsCommit() { + const changedPackages = await getChangedPackages(); + const packageInfo = await getPackageInfo(); + const packageLocations = []; + for (const packageName of changedPackages) { + const packageDesc = packageInfo.find(info => info.name === packageName); + if (packageDesc) { + const packageJson = require(`${packageDesc.location}/package.json`); + + if (packageJson && packageJson.scripts['api-report']) { + const apiReportSpinner = ora( + ` Creating API report for ${packageName}` + ).start(); + packageLocations.push(packageDesc.location); + execSync(`yarn api-report`, { cwd: packageDesc.location }); + apiReportSpinner.stopAndPersist({ + symbol: '✅' + }); + } + } + } + + const hasDiff = await git.diff(); + + if (!hasDiff) return; + + const gitSpinner = ora(' Creating automated API reports commit').start(); + await git.add('.'); + + await git.commit('[AUTOMATED]: API Reports'); + gitSpinner.stopAndPersist({ + symbol: '✅' + }); +} + +exports.doApiReportsCommit = doApiReportsCommit; diff --git a/tools/gitHooks/prepush.js b/tools/gitHooks/prepush.js index b52a41cf9cb..8ff853564e3 100644 --- a/tools/gitHooks/prepush.js +++ b/tools/gitHooks/prepush.js @@ -17,6 +17,7 @@ const { doPrettierCommit } = require('./prettier'); const { doLicenseCommit } = require('./license'); +const { doApiReportsCommit } = require('./api-report'); const { resolve } = require('path'); const simpleGit = require('simple-git/promise'); const chalk = require('chalk'); @@ -57,6 +58,9 @@ $ git stash pop // Validate License headers exist await doLicenseCommit(changedFiles); + // Generate API reports + await doApiReportsCommit(); + console.log(chalk` Pre-Push Validation Succeeded diff --git a/yarn.lock b/yarn.lock index 933e487e34c..5c88f1ef707 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1787,6 +1787,69 @@ npmlog "^4.1.2" write-file-atomic "^2.3.0" +"@microsoft/api-documenter@7.7.12": + version "7.7.12" + resolved "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.7.12.tgz#e355cd24caefbf831686b684c09918906894ff5c" + integrity sha512-FVd0c+DEz+HntBmtRsTTslVvBagx0FqGC+rzF8jnVDJbiW6xkwjwfTj/VKqNNdz821sEPp+eAJgGh7s0Nyx3Iw== + dependencies: + "@microsoft/api-extractor-model" "7.7.7" + "@microsoft/node-core-library" "3.19.3" + "@microsoft/ts-command-line" "4.3.10" + "@microsoft/tsdoc" "0.12.14" + colors "~1.2.1" + js-yaml "~3.13.1" + resolve "1.8.1" + +"@microsoft/api-extractor-model@7.7.7": + version "7.7.7" + resolved "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.7.7.tgz#1d15eae7a19b72abbfca9053f200fe79b6f9d755" + integrity sha512-822kyHMEx2sl+KnBioEiFoTIXuz/4pYBo94nQ4AMqb9BFvY9I1AZUPtC4HFh2zcXQqpFLpKKC55s/o8UOze2wQ== + dependencies: + "@microsoft/node-core-library" "3.19.3" + "@microsoft/tsdoc" "0.12.14" + +"@microsoft/api-extractor@7.7.8": + version "7.7.8" + resolved "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.7.8.tgz#19b0bca8a2113d4ded55a270266bc2b802de1a43" + integrity sha512-XNO6Dk6ByfJq24Cn1/j0B0F16ZtwYnEC/sxgB/M0wTphBdBlHjRXZmxofmjirBBj9f7vG4UJ18IOIZRLbhGFPw== + dependencies: + "@microsoft/api-extractor-model" "7.7.7" + "@microsoft/node-core-library" "3.19.3" + "@microsoft/ts-command-line" "4.3.10" + "@microsoft/tsdoc" "0.12.14" + colors "~1.2.1" + lodash "~4.17.15" + resolve "1.8.1" + source-map "~0.6.1" + typescript "~3.7.2" + +"@microsoft/node-core-library@3.19.3": + version "3.19.3" + resolved "https://registry.npmjs.org/@microsoft/node-core-library/-/node-core-library-3.19.3.tgz#cf09ddb2905a29b32956d4a88f9d035a00637be9" + integrity sha512-rJ+hT6+XK5AESbhn31YBnHKpZSFKCmqHCRZyK9+jyWwav1HXv0qzuXnFvnyrO0MZyJ6rH0seWOZVWbU5KGv1tg== + dependencies: + "@types/node" "10.17.13" + colors "~1.2.1" + fs-extra "~7.0.1" + jju "~1.4.0" + semver "~5.3.0" + timsort "~0.3.0" + z-schema "~3.18.3" + +"@microsoft/ts-command-line@4.3.10": + version "4.3.10" + resolved "https://registry.npmjs.org/@microsoft/ts-command-line/-/ts-command-line-4.3.10.tgz#fcb4f5ea43c93d17db6cc810bbee39ea32b2a86d" + integrity sha512-AgxArGqPt0H5WTo3fxNFP3Blm3obkCCopVG9kwIo+/mMdXaj6qMDn6+8Bv8+5Nke3CvvXpKAZtu3IaGY5cV1Hg== + dependencies: + "@types/argparse" "1.0.33" + argparse "~1.0.9" + colors "~1.2.1" + +"@microsoft/tsdoc@0.12.14": + version "0.12.14" + resolved "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.14.tgz#0e0810a0a174e50e22dfe8edb30599840712f22d" + integrity sha512-518yewjSga1jLdiLrcmpMFlaba5P+50b0TWNFUpC+SL9Yzf0kMi57qw+bMl+rQ08cGqH1vLx4eg9YFUbZXgZ0Q== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -2003,6 +2066,11 @@ resolved "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.0.7.tgz#0cd915785ec4190f08a3a6acc9b61fc38fb5f1a9" integrity sha512-8UT/J+xqCYfn3fKtOznAibsHpiuDshCb0fwgWxRazTT19Igp9ovoXMPhXyLD6m3CKQGTMHgqoxaFfMWaL40Rnw== +"@types/argparse@1.0.33": + version "1.0.33" + resolved "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.33.tgz#2728669427cdd74a99e53c9f457ca2866a37c52d" + integrity sha512-VQgHxyPMTj3hIlq9SY1mctqx+Jj8kpQfoLvDlVSDNOyuYs8JYfkuY3OW/4+dO657yPmNhHpePRx0/Tje5ImNVQ== + "@types/body-parser@*": version "1.17.1" resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897" @@ -2151,6 +2219,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-8.10.54.tgz#1c88eb253ac1210f1a5876953fb70f7cc4928402" integrity sha512-kaYyLYf6ICn6/isAyD4K1MyWWd5Q3JgH6bnMN089LUx88+s4W8GvK9Q6JMBVu5vsFFp7pMdSxdKmlBXwH/VFRg== +"@types/node@10.17.13": + version "10.17.13" + resolved "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c" + integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== + "@types/node@8.10.59": version "8.10.59" resolved "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz#9e34261f30183f9777017a13d185dfac6b899e04" @@ -2792,7 +2865,7 @@ arg@^4.1.0: resolved "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz#485f8e7c390ce4c5f78257dbea80d4be11feda4c" integrity sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw== -argparse@^1.0.7: +argparse@^1.0.7, argparse@~1.0.9: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4336,6 +4409,11 @@ colors@^1.1.0, colors@^1.1.2, colors@^1.3.3: resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== +colors@~1.2.1: + version "1.2.5" + resolved "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc" + integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== + colour@~0.7.1: version "0.7.1" resolved "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" @@ -4371,7 +4449,7 @@ commander@2.20.0: resolved "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== -commander@^2.12.1, commander@^2.20.0: +commander@^2.12.1, commander@^2.20.0, commander@^2.7.1: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -6696,7 +6774,7 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^7.0.1: +fs-extra@^7.0.1, fs-extra@~7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -8828,7 +8906,7 @@ jest-worker@^24.0.0, jest-worker@^24.9.0: merge-stream "^2.0.0" supports-color "^6.1.0" -jju@^1.1.0: +jju@^1.1.0, jju@~1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" integrity sha1-o6vicYryQaKykE+EpiWXDzia4yo= @@ -8857,7 +8935,7 @@ js-tokens@^3.0.2: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.13.1, js-yaml@^3.13.1: +js-yaml@3.13.1, js-yaml@^3.13.1, js-yaml@~3.13.1: version "3.13.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -9573,7 +9651,7 @@ lodash.flattendeep@^4.4.0: resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= -lodash.get@^4.4.2: +lodash.get@^4.0.0, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= @@ -9603,6 +9681,11 @@ lodash.isboolean@^3.0.3: resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= +lodash.isequal@^4.0.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + lodash.isinteger@^4.0.4: version "4.0.4" resolved "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" @@ -9716,7 +9799,7 @@ lodash.values@^2.4.1: dependencies: lodash.keys "~2.4.1" -lodash@4.17.15, lodash@^4.0.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1: +lodash@4.17.15, lodash@^4.0.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@~4.17.15: version "4.17.15" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -11465,7 +11548,7 @@ path-parse@1.0.5: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME= -path-parse@^1.0.6: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== @@ -12504,6 +12587,13 @@ resolve@1.15.1: dependencies: path-parse "^1.0.6" +resolve@1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== + dependencies: + path-parse "^1.0.5" + resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0: version "1.12.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" @@ -14120,6 +14210,11 @@ timers-ext@^0.1.5: es5-ext "~0.10.46" next-tick "1" +timsort@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + tiny-queue@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" @@ -14461,7 +14556,7 @@ typedoc@0.16.11: typedoc-default-themes "^0.7.2" typescript "3.7.x" -typescript@3.7.x: +typescript@3.7.x, typescript@~3.7.2: version "3.7.5" resolved "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== @@ -14886,6 +14981,11 @@ validator@^10.11.0: resolved "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== +validator@^8.0.0: + version "8.2.0" + resolved "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" + integrity sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== + value-or-function@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" @@ -15679,6 +15779,17 @@ yn@3.1.1: resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +z-schema@~3.18.3: + version "3.18.4" + resolved "https://registry.npmjs.org/z-schema/-/z-schema-3.18.4.tgz#ea8132b279533ee60be2485a02f7e3e42541a9a2" + integrity sha512-DUOKC/IhbkdLKKiV89gw9DUauTV8U/8yJl1sjf6MtDmzevLKOF2duNJ495S3MFVjqZarr+qNGCPbkg4mu4PpLw== + dependencies: + lodash.get "^4.0.0" + lodash.isequal "^4.0.0" + validator "^8.0.0" + optionalDependencies: + commander "^2.7.1" + zip-stream@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.2.tgz#841efd23214b602ff49c497cba1a85d8b5fbc39c"