diff --git a/types/lasso/index.d.ts b/types/lasso/index.d.ts new file mode 100644 index 0000000000..64546a91c3 --- /dev/null +++ b/types/lasso/index.d.ts @@ -0,0 +1,53 @@ +// Type definitions for lasso 2.4 +// Project: https://github.com/lasso-js/lasso +// Definitions by: Timur Manyanov +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import Lasso, { LassoConfig, LassoResource, LassoPage } from './lib/Lasso'; +import LassoContext from './lib/LassoContext'; + +export namespace transforms { + function createTransformer(unfilteredTransforms: any[], lassoContext: LassoContext, callback: (err: Error | null, result?: any) => any): void; +} + +export namespace writers { + interface Writer { + lasso: Lasso; + config: LassoConfig; + } + + function Writer(impl: any): Writer; + function fileWriter(fileWriterConfig: any, lassoConfig: LassoConfig): any; + function createWriter(impl: any): Writer; +} + +export const defaultConfig: LassoConfig; + +export const defaultConfigBaseDir: string; + +export const defaultConfigFilename: string | null; + +export const lassoPage: LassoPage; + +export const lassoResource: LassoResource; + +export function getDefaultLasso(): Lasso; + +export function create(config?: LassoConfig | string, baseDir?: string, filename?: string): Lasso; + +export function configure(config?: LassoConfig | string, baseDir?: string, filename?: string): void; + +export function setDevelopmentMode(): void; + +export function createFlagSet(flags: any): any; + +export function isFlagSet(o: any): boolean; + +export function flushAllCaches(callback?: any): void; + +export function handleWatchedFileChanged(path: string): void; + +export function clearCaches(): void; + +export function getClientPath(path: string, options?: any): string; diff --git a/types/lasso/lasso-tests.ts b/types/lasso/lasso-tests.ts new file mode 100644 index 0000000000..bc944817ee --- /dev/null +++ b/types/lasso/lasso-tests.ts @@ -0,0 +1,201 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { transforms, configure, create, lassoPage, getDefaultLasso } from 'lasso'; +import { serveStatic } from 'lasso/middleware'; +import { enable } from 'lasso/node-require-no-op'; +import LassoContext from 'lasso/lib/LassoContext'; +import LassoPageResult from 'lasso/lib/LassoPageResult'; + +// $ExpectType void +configure('lasso-config.json'); + +// $ExpectType void +configure({}); + +// $ExpectType Lasso +create({}); + +const lasso = getDefaultLasso(); +// $ExpectType Lasso +lasso; + +// $ExpectType Promise +lassoPage({ + name: 'my-page', + dependencies: [ + './style.less', + 'require-run: ./main' + ] +}, +(err, lassoPageResult) => { + if (err) { + console.log('Failed to lasso page: ', err); + return; + } + + // $ExpectType string + lassoPageResult.getHeadHtml(); + + // $ExpectType string + lassoPageResult.getBodyHtml(); +}); + +lassoPage({ + dependencies: [{ + path: './hello-mobile.js', + 'if-flag': 'mobile' + }], + flags: ['mobile', 'foo', 'bar'] +}); + +configure({ + cspNonceProvider(out) { + const res = out.stream; + + return res.csp && res.csp.nonce; + } +}); + +configure({ + require: { + extensions: [ '.js' ], + transforms: [ 'deamdify' ] + } +}); + +// $ExpectType Lasso +lasso.on('afterLassoPage', (event) => { + const lassoPageResult: LassoPageResult = event.result; + const fingerprints = lassoPageResult.getInlineCodeFingerprints(); + // $ExpectType string + fingerprints.map(fingerprint => `script-src 'self' 'sha256-${fingerprint}'`).join('; '); +}); + +const dependencies = lasso.dependencies; + +// $ExpectType void +dependencies.registerJavaScriptType('my-js-type', require('./dependency-my-js-type')); // tslint:disable-line: no-var-requires + +// $ExpectType void +dependencies.registerJavaScriptType('my-custom-type', { + properties: { + path: 'string' + }, + + init(context: any, callback: any) { + if (!this.path) { + throw new Error('"path" is required'); + } + + this.path = this.resolvePath(this.path); + callback(); + }, + + read(context: any, callback: any) { + const path = this.path; + + fs.readFile(path, {encoding: 'utf8'}, (err, src) => { + if (err) { + return callback(err); + } + + // myCompiler.compile(src, callback); + }); + }, + + getSourceFile() { + return this.path; + } +}); + +// $ExpectType void +dependencies.registerStyleSheetType('my-custom-type', {}); + +// $ExpectType void +dependencies.registerPackageType('dir', { + properties: { + path: 'string' + }, + + init(context: any, callback: any) { + let path = this.path; + + if (!path) { + callback(new Error('"path" is required')); + } + + this.path = path = this.resolvePath(path); + + fs.stat(path, (err, stat) => { + if (err) { + return callback(err); + } + + if (!stat.isDirectory()) { + return callback(new Error('Directory expected: ' + path)); + } + + callback(); + }); + }, + + getDependencies(context: any, callback: any) { + const dir = this.path; + + fs.readdir(dir, (err, filenames) => { + if (err) { + return callback(err); + } + + const dependencies = filenames.map(filename => path.join(dir, filename)); + + callback(null, dependencies); + }); + }, + + getDir() { + return this.path; + } +}); + +// $ExpectType void +dependencies.registerRequireExtension('test', (path: string, context: any, callback: any) => { + callback(null, "exports.sayHello = function() { console.log('Hello!'); }"); +}); + +// $ExpectType void +lasso.lassoResource('path/to/foo.png', (err: any, result: any) => { + if (err) { + console.log(err); + } else { + const url = result.url; + } +}); + +// $ExpectType void +lasso.addTransform(require('./my-transform')); // tslint:disable-line: no-var-requires + +// $ExpectType void +lasso.addTransform({ + contentType: 'js', + name: module.id, + stream: false, + transform(code: string, lassoContext: LassoContext) { + return code.toUpperCase(); + } +}); + +// $ExpectType void +transforms.createTransformer([], new LassoContext(), (err, result) => {}); + +// $ExpectType RequestHandler +serveStatic(); + +// $ExpectType RequestHandler +serveStatic({ + lasso, + sendOptions: {} +}); + +// $ExpectType void +enable(); diff --git a/types/lasso/lib/Lasso.d.ts b/types/lasso/lib/Lasso.d.ts new file mode 100644 index 0000000000..56e0d195f5 --- /dev/null +++ b/types/lasso/lib/Lasso.d.ts @@ -0,0 +1,79 @@ +/// + +import { EventEmitter } from 'events'; +import LassoContext from './LassoContext'; +import { Bundle, DependencyConfig, DependencyRegistry } from './dependencies'; +import { writers } from '../index'; +import LassoPageResult from './LassoPageResult'; + +export interface PageConfig { + name?: string; + dependencies: DependencyConfig[] | string[] | string | null; + flags?: string[]; + from?: string; + packagePath?: string; + packagePaths?: string[]; + lassoContext?: LassoContext; + cache?: any; + cacheKey?: string; + pageName?: string; + data?: any; +} + +export type Callback = (err: Error | null, result?: any) => any; +export type LassoPage = (options: PageConfig, callback?: (err: Error | null, result: LassoPageResult) => void) => Promise; +export type LassoResource = (path: string, options?: any, callback?: Callback) => void; + +export interface CustomPlugin { + plugin: string; + config: any; +} + +export interface LassoConfig { + baseDir?: string; + plugins?: string[] | CustomPlugin[]; + require?: any; + outputDir?: string; + urlPrefix?: string; + fingerprintsEnabled?: boolean; + includeSlotNames?: boolean; + minify?: boolean; + minifyJS?: boolean; + minifyCSS?: boolean; + minifyInlineOnly?: boolean; + minifyInlineJSOnly?: boolean; + minifyInlineCSSOnly?: boolean; + resolveCssUrls?: boolean; + relativeUrlsEnabled?: boolean; + bundlingEnabled?: boolean; + bundles?: Bundle[]; + noConflict?: string; + + cspNonceProvider?(out: any): string; + fingerprintInlineCode?(code: any): string; +} + +export default class Lasso extends EventEmitter { + constructor(config: LassoConfig); + + config: LassoConfig; + lassoCacheLookup: any; + dependencies: DependencyRegistry; + writer: writers.Writer; + + initPlugins(): void; + createAppBundleMappings(bundleSetConfig: any, lassoContext: LassoContext, callback: Callback): any; + buildPageBundles(options: any, lassoContext: LassoContext, callback: Callback): void; + getAppBundleMappingsCached(bundleSetConfig: any, lassoContext: LassoContext, callback: Callback): void; + buildLassoCacheKey(lassoContext: LassoContext): { value: string; parts: string[]; }; + getLassoCache(lassoContext: LassoContext): any; + getConfig(): LassoConfig; + getJavaScriptDependencyHtml(url: string, attributes?: any): string; + getCSSDependencyHtml(url: string, attributes?: any): string; + createLassoContext(options?: any): LassoContext; + setCSPNonceProvider(func: any): any; + addTransform(transform: any): void; + getDependencyRegistry(): DependencyRegistry; + lassoPage: LassoPage; + lassoResource: LassoResource; +} diff --git a/types/lasso/lib/LassoContext.d.ts b/types/lasso/lib/LassoContext.d.ts new file mode 100644 index 0000000000..ae01277558 --- /dev/null +++ b/types/lasso/lib/LassoContext.d.ts @@ -0,0 +1,21 @@ +/// +import { EventEmitter } from 'events'; +import Lasso from './Lasso'; +import { DependencyRegistry } from './dependencies'; +import { writers } from '../index'; + +export default class LassoContext extends EventEmitter { + constructor(); + + LassoContext: boolean; + basePath?: string; + contentType?: string; + data?: any; + dependencyRegistry: DependencyRegistry; + flags: any[]; + config: any; + writer: writers.Writer; + lasso: Lasso; + cache: any; + options: any; +} diff --git a/types/lasso/lib/LassoPageResult.d.ts b/types/lasso/lib/LassoPageResult.d.ts new file mode 100644 index 0000000000..8d51ae052f --- /dev/null +++ b/types/lasso/lib/LassoPageResult.d.ts @@ -0,0 +1,32 @@ +import LassoContext from './LassoContext'; + +export default interface LassoPageResult { + addFile(filePath: string, contentType: string, isAsync: boolean, slot: any): void; + addUrl(url: string, slot: any, contentType: string, isAsync: boolean): void; + deserialize(reader: any, callback: any): void; + getBodyHtml(data?: any): string; + getCSSFiles(): any[]; + getCSSUrls(): any[]; + getFileByAsyncBundleName(bundleName: string): any; + getFileByBundleName(bundleName: string): any; + getFilePathsByContentType(...args: any[]): void; + getHeadHtml(data?: any): string; + getHtmlBySlot(): any; + getHtmlForSlot(slotName: string, data?: any): any; + getInlineCodeFingerprints(): string[]; + getJavaScriptFiles(): any[]; + getJavaScriptUrls(): any[]; + getOutputFiles(): any[]; + getOutputFilesWithInfo(...args: any[]): void; + getSlotHtml(slotName: string, data?: any): any; + getUrlByAsyncBundleName(bundleName: string): any; + getUrlByBundleName(bundleName: string): any; + getUrlsForSlot(slot: any): any; + htmlSlotsToJSON(indentation: any): any; + registerBundle(bundle: any, async: any, lassoContext: LassoContext): void; + registerResource(resource: any): void; + serialize(lassoPageResult: LassoPageResult): any; + setHtmlBySlot(htmlBySlot: any): void; + setInlineCodeFingerprints(inlineCodeFingerprints: string[]): void; + toJSON(): any; +} diff --git a/types/lasso/lib/dependencies.d.ts b/types/lasso/lib/dependencies.d.ts new file mode 100644 index 0000000000..682b6b3c30 --- /dev/null +++ b/types/lasso/lib/dependencies.d.ts @@ -0,0 +1,112 @@ +/// + +import LassoContext from './LassoContext'; +import { EventEmitter } from 'events'; + +export type Callback = (err: Error | null, result?: any) => any; + +export interface Bundle { + name: string; + dependencies: Array; +} + +export interface DependencyConfig { + type?: string; + attributes?: { + integrity: string; + crossorigin: string; + }; + inline?: string; + slot?: string; + 'css-slot'?: string; + 'js-slot'?: string; + url?: string; + path?: string; + external?: boolean; + 'if-flag'?: string; + 'if-not-flag'?: string; + if?: string; + from?: string; + to?: string; + require?: string; + 'require-run'?: string; + dependencies?: Array; +} + +export interface Dependency extends EventEmitter, DependencyConfig { + _packageDependency?: boolean; + contentType?: string; + properties?: { [key: string]: string }; + + (dependencyConfig: DependencyConfig, dirname: string, filename?: string): Dependency; + calculateKey(lassoContext: LassoContext, callback: Callback): any; + doCalculateKey(lassoContext: LassoContext, callback: Callback): any; + calculateKeyFromProps(): string; + createPackageManifest(manifest?: any, dirname?: string, filename?: string): any; + createReadStream(lassoContext: LassoContext): any; + doGetLastModified(lassoContext: any, callback: Callback): any; + getContentType(): any; + getDefaultBundleName(pageBundleName?: string, lassoContext?: LassoContext): string; + getDir(): string | null; + getFileLastModified(path: string, callback: Callback): any; + getJavaScriptSlot(): any; + getKey(): any; + getLastModified(lassoContext: LassoContext, callback: Callback): any; + getPackageManifest(lassoContext: LassoContext, callback: Callback): any; + getParentManifestDir(): string; + getParentManifestPath(): string; + getPropsKey(): any; + getReadCacheKey(): any; + getSlot(): any; + getSourceFile(): any; + getStyleSheetSlot(): any; + hasContent(): boolean; + hasModifiedFingerprint(): boolean; + init(lassoContext: LassoContext, callback: Callback): any; + doInit(lassoContext: LassoContext, callback: Callback): void; + inspect(): any; + isCompiled(): boolean; + isExternalResource(): boolean; + isInPlaceDeploymentAllowed(): boolean; + isJavaScript(): boolean; + isPackageDependency(): boolean; + isPageBundleOnlyDependency(): boolean; + isStyleSheet(): boolean; + onAddToAsyncPageBundle(bundle: Bundle, lassoContext: LassoContext): void; + onAddToPageBundle(bundle: Bundle, lassoContext: LassoContext): void; + read(context: any, callback: Callback): any; + resolvePath(path: string, from?: string): string; + set(props: any): void; + shouldCache(lassoContext: LassoContext): boolean; +} + +export interface DependencyRegistry { + registeredTypes: any; + extensions: any; + requireExtensions: any; + requireExtensionNames: any; + + addNormalizer(normalizerFunc: any): any; + createDependency(config: any, dirname: string, filename?: string): any; + createRequireHandler(path: string, lassoContext: LassoContext, userOptions: any): any; + createResourceTransformType(transformFunc: any): any; + getRequireExtensionNames(): any; + getRequireHandler(path: string, lassoContext: LassoContext): any; + getType(type: string): any; + normalizeDependencies(dependencies: any[], dirname: string, filename: string, callback: Callback): any; + registerDefaults(): void; + registerExtension(extension: string, type: string): void; + registerJavaScriptType(type: string, mixins: any): void; + registerPackageType(type: string, mixins: any): void; + registerRequireExtension(ext: string, options: any): void; + registerRequireType(type: string, options: any): void; + registerStyleSheetType(type: string, mixins: any): void; + registerType(type: string, mixins: any): void; + typeForPath(path: string): string; +} + +export function createRegistry(): DependencyRegistry; + +export function isRegistry(o: any): boolean; + +export function isDependency(d: any): boolean; diff --git a/types/lasso/middleware.d.ts b/types/lasso/middleware.d.ts new file mode 100644 index 0000000000..948de1a03f --- /dev/null +++ b/types/lasso/middleware.d.ts @@ -0,0 +1,9 @@ +import { RequestHandler } from 'express'; +import Lasso from './lib/Lasso'; + +export interface MiddlewareOptions { + lasso?: Lasso; + sendOptions?: any; +} + +export function serveStatic(options?: MiddlewareOptions): RequestHandler; diff --git a/types/lasso/node-require-no-op.d.ts b/types/lasso/node-require-no-op.d.ts new file mode 100644 index 0000000000..713a4aafe4 --- /dev/null +++ b/types/lasso/node-require-no-op.d.ts @@ -0,0 +1 @@ +export function enable(...extensions: string[]): void; diff --git a/types/lasso/tsconfig.json b/types/lasso/tsconfig.json new file mode 100644 index 0000000000..2386e1e1f5 --- /dev/null +++ b/types/lasso/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "dom", + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "lasso-tests.ts", + "middleware.d.ts", + "node-require-no-op.d.ts", + "lib/dependencies.d.ts", + "lib/Lasso.d.ts", + "lib/LassoContext.d.ts" + ] +} diff --git a/types/lasso/tslint.json b/types/lasso/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/lasso/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +}