diff --git a/packages/codemaker/lib/codemaker.ts b/packages/codemaker/lib/codemaker.ts index 9e50dd1766..2ecb1183d3 100644 --- a/packages/codemaker/lib/codemaker.ts +++ b/packages/codemaker/lib/codemaker.ts @@ -16,6 +16,10 @@ export class CodeMaker { private readonly files = new Array(); private readonly excludes = new Array(); + public get currentIndentLength(): number { + return this.currIndent * this.indentation; + } + /** * Formats an block open statement. */ @@ -24,7 +28,7 @@ export class CodeMaker { /** * Formats a block close statement. */ - public closeBlockFormatter: (s?: string) => string = () => '}'; + public closeBlockFormatter: (s?: string) => string | false = () => '}'; /** * Saves all the files created in this code maker. @@ -102,7 +106,7 @@ export class CodeMaker { /** * Same as `close`. */ - public unindent(textAfter?: string) { + public unindent(textAfter?: string | false) { this.close(textAfter); } @@ -118,10 +122,14 @@ export class CodeMaker { /** * Decreases the indentation level by `indentation` for the next line. * @param textAfter Text to emit in the line after indentation was decreased. + * If `false` no line will be emitted at all, but the indent + * counter will be decremented. */ - public close(textAfter?: string) { + public close(textAfter?: string | false) { this.currIndent--; - this.line(textAfter); + if (textAfter !== false) { + this.line(textAfter); + } } /** @@ -170,13 +178,11 @@ export class CodeMaker { return caseutils.toSnakeCase(s, sep); } - private makeIndent() { - let spaces = ''; - for (let i = 0; i < this.currIndent; ++i) { - for (let j = 0; j < this.indentation; ++j) { - spaces += ' '; - } + private makeIndent(): string { + const length = this.currentIndentLength; + if (length <= 0) { + return ''; } - return spaces; + return ' '.repeat(length); } } diff --git a/packages/jsii-pacmak/lib/targets/python.ts b/packages/jsii-pacmak/lib/targets/python.ts index 16e6feb547..49d61ccf54 100644 --- a/packages/jsii-pacmak/lib/targets/python.ts +++ b/packages/jsii-pacmak/lib/targets/python.ts @@ -1,13 +1,10 @@ import * as spec from '@jsii/spec'; import { CodeMaker, toSnakeCase } from 'codemaker'; import * as escapeStringRegexp from 'escape-string-regexp'; -import * as fs from 'fs-extra'; import * as reflect from 'jsii-reflect'; -import * as lockfile from 'lockfile'; -import * as os from 'os'; import * as path from 'path'; import { Generator, GeneratorOptions } from '../generator'; -import { info, warn } from '../logging'; +import { warn } from '../logging'; import { md2rst } from '../markdown'; import { Target, TargetOptions } from '../target'; import { shell } from '../util'; @@ -33,11 +30,7 @@ import { die, toPythonIdentifier } from './python/util'; // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports const spdxLicenseList = require('spdx-license-list'); -const VENV_BIN = process.platform === 'win32' ? 'Scripts' : 'bin'; - export default class Python extends Target { - private static BLACK_PATH?: Promise; - protected readonly generator: PythonGenerator; public constructor(options: TargetOptions) { @@ -48,16 +41,6 @@ export default class Python extends Target { public async generateCode(outDir: string, tarball: string): Promise { await super.generateCode(outDir, tarball); - - // Using a static variable as a lock to prevent racing. Since blackPath() uses - // Promise APIs from fs and os modules (that use libuv), an additional lock is required. - if (Python.BLACK_PATH === undefined) { - Python.BLACK_PATH = this.blackPath(); - } - // We'll just run "black" on that now, to make the generated code a little more readable. - await shell(await Python.BLACK_PATH, ['--py36', outDir], { - cwd: outDir, - }); } public async build(sourceDir: string, outDir: string): Promise { @@ -79,60 +62,6 @@ export default class Python extends Target { ); } } - - private async blackPath(): Promise { - if (await isPresent('black')) { - return 'black'; - } - - const blackInstallDir = path.join( - os.homedir(), - '.jsii-cache', - 'python-black', - ); - const venvRoot = path.join(blackInstallDir, 'venv'); - const black = path.join(venvRoot, VENV_BIN, 'black'); - - await fs.mkdirp(blackInstallDir); - const lockFile = path.join(blackInstallDir, 'busy.lock'); - - await lock(lockFile); - - try { - const existing = await cachedBlackPath(); - if (existing != null) { - return existing; - } - - info( - `No existing black installations. install afresh at ${blackInstallDir}...`, - ); - - await shell('python3', ['-m', 'venv', venvRoot], { - cwd: blackInstallDir, - }); - await shell( - path.join(venvRoot, VENV_BIN, 'pip'), - ['install', '--no-input', 'black'], - { cwd: blackInstallDir }, - ); - } finally { - await unlock(lockFile); - } - - return (await cachedBlackPath())!; - - async function cachedBlackPath() { - const suffixes = process.platform === 'win32' ? ['.exe', '.bat'] : ['']; - for (const suffix of suffixes) { - // eslint-disable-next-line no-await-in-loop - if (await fs.pathExists(`${black}${suffix}`)) { - return `${black}${suffix}`; - } - } - return undefined; - } - } } // Approximating existence check using `which`, falling back on `pip3 show`. @@ -307,6 +236,7 @@ interface PythonTypeOpts { abstract class BasePythonClassType implements PythonType, ISortableType { protected bases: spec.TypeReference[]; protected members: PythonBase[]; + protected readonly separateMembers: boolean = true; public constructor( protected readonly generator: PythonGenerator, @@ -369,21 +299,29 @@ abstract class BasePythonClassType implements PythonType, ISortableType { context = { ...context, nestingScope: this.fqn! }; const classParams = this.getClassParams(context); - const bases = classParams.length > 0 ? `(${classParams.join(', ')})` : ''; + openSignature(code, 'class', this.pythonName, classParams); - code.openBlock(`class ${this.pythonName}${bases}`); this.generator.emitDocString(code, this.docs, { documentableItem: `class-${this.pythonName}`, + trailingNewLine: true, }); - this.emitPreamble(code, context); + const preamble = this.emitPreamble; + if (preamble) { + preamble(code, context); + } if (this.members.length > 0) { const resolver = this.boundResolver(context.resolver); + let shouldSeparate = preamble != null; for (const member of sortMembers(this.members, resolver)) { + if (shouldSeparate) { + code.line(); + } + shouldSeparate = this.separateMembers; member.emit(code, { ...context, resolver }); } - } else { + } else if (!preamble) { code.line('pass'); } @@ -399,9 +337,10 @@ abstract class BasePythonClassType implements PythonType, ISortableType { protected abstract getClassParams(context: EmitContext): string[]; - protected emitPreamble(_code: CodeMaker, _context: EmitContext) { - return; - } + protected abstract readonly emitPreamble?: ( + code: CodeMaker, + context: EmitContext, + ) => void; } interface BaseMethodOpts { @@ -505,7 +444,7 @@ abstract class BaseMethod implements PythonBase { ); const paramType = toTypeName(param).pythonType(context); - const paramDefault = param.optional ? '=None' : ''; + const paramDefault = param.optional ? ' = None' : ''; pythonParams.push(`${paramName}: ${paramType}${paramDefault}`); } @@ -537,7 +476,7 @@ abstract class BaseMethod implements PythonBase { for (const prop of liftedProperties) { const paramName = toPythonParameterName(prop.name); const paramType = toTypeName(prop).pythonType(context); - const paramDefault = prop.optional ? '=None' : ''; + const paramDefault = prop.optional ? ' = None' : ''; pythonParams.push(`${paramName}: ${paramType}${paramDefault}`); } @@ -580,8 +519,13 @@ abstract class BaseMethod implements PythonBase { ), ); - code.openBlock( - `def ${this.pythonName}(${pythonParams.join(', ')}) -> ${returnType}`, + openSignature( + code, + 'def', + this.pythonName, + pythonParams, + false, + returnType, ); this.generator.emitDocString(code, this.docs, { arguments: documentableArgs, @@ -646,7 +590,7 @@ abstract class BaseMethod implements PythonBase { .map((p) => p.pythonName) .map((v) => `${v}=${v}`); - code.line(`${argName} = ${typeName}(${assignments.join(', ')})`); + assignCallResult(code, argName, typeName, assignments); code.line(); } @@ -773,8 +717,13 @@ abstract class BaseProperty implements PythonBase { if (renderAbstract && this.abstract) { code.line('@abc.abstractmethod'); } - code.openBlock( - `def ${this.pythonName}(${this.implicitParameter}) -> ${pythonType}`, + openSignature( + code, + 'def', + this.pythonName, + [this.implicitParameter], + true, + pythonType, ); this.generator.emitDocString(code, this.docs, { documentableItem: `prop-${this.pythonName}`, @@ -792,12 +741,18 @@ abstract class BaseProperty implements PythonBase { code.closeBlock(); if (!this.immutable) { + code.line(); code.line(`@${this.pythonName}.setter`); if (renderAbstract && this.abstract) { code.line('@abc.abstractmethod'); } - code.openBlock( - `def ${this.pythonName}(${this.implicitParameter}, value: ${pythonType}) -> None`, + openSignature( + code, + 'def', + this.pythonName, + [this.implicitParameter, `value: ${pythonType}`], + false, + 'None', ); if ( (this.shouldEmitBody || forceEmitBody) && @@ -817,11 +772,14 @@ abstract class BaseProperty implements PythonBase { class Interface extends BasePythonClassType { public emit(code: CodeMaker, context: EmitContext) { context = { ...context, nestingScope: this.fqn! }; - code.line(`@jsii.interface(jsii_type="${this.fqn}")`); + emitList(code, '@jsii.interface(', [`jsii_type="${this.fqn}"`], ')'); // First we do our normal class logic for emitting our members. super.emit(code, context); + code.line(); + code.line(); + // Then, we have to emit a Proxy class which implements our proxy interface. const proxyBases: string[] = this.bases.map( (b) => @@ -830,16 +788,18 @@ class Interface extends BasePythonClassType { typeAnnotation: false, })})`, ); - code.openBlock( - `class ${this.getProxyClassName()}(${proxyBases.join(', ')})`, - ); + openSignature(code, 'class', this.getProxyClassName(), proxyBases); this.generator.emitDocString(code, this.docs, { documentableItem: `class-${this.pythonName}`, + trailingNewLine: true, }); code.line(`__jsii_type__ = "${this.fqn}"`); if (this.members.length > 0) { for (const member of this.members) { + if (this.separateMembers) { + code.line(); + } member.emit(code, context, { forceEmitBody: true }); } } else { @@ -859,12 +819,15 @@ class Interface extends BasePythonClassType { return params; } - protected emitPreamble(code: CodeMaker, _context: EmitContext) { + protected readonly emitPreamble = ( + code: CodeMaker, + _context: EmitContext, + ) => { code.line('@builtins.staticmethod'); code.openBlock('def __jsii_proxy_class__()'); code.line(`return ${this.getProxyClassName()}`); code.closeBlock(); - } + }; private getProxyClassName(): string { return `_${this.pythonName}Proxy`; @@ -886,6 +849,7 @@ class InterfaceProperty extends BaseProperty { } class Struct extends BasePythonClassType { + protected readonly emitPreamble = undefined; protected directMembers = new Array(); public addMember(member: PythonBase): void { @@ -899,17 +863,16 @@ class Struct extends BasePythonClassType { context = { ...context, nestingScope: this.fqn! }; const baseInterfaces = this.getClassParams(context); - code.line( - `@jsii.data_type(jsii_type="${ - this.fqn - }", jsii_struct_bases=[${baseInterfaces.join( - ', ', - )}], name_mapping=${this.propertyMap()})`, - ); - code.openBlock(`class ${this.pythonName}(${baseInterfaces.join(', ')})`); + code.indent('@jsii.data_type('); + code.line(`jsii_type=${JSON.stringify(this.fqn)},`); + emitList(code, 'jsii_struct_bases=[', baseInterfaces, '],'); + assignDictionary(code, 'name_mapping', this.propertyMap(), ',', true); + code.unindent(')'); + openSignature(code, 'class', this.pythonName, baseInterfaces); this.emitConstructor(code, context); for (const member of this.allMembers) { + code.line(); this.emitGetter(member, code, context); } @@ -961,7 +924,7 @@ class Struct extends BasePythonClassType { ? [implicitParameter, '*', ...kwargs] : [implicitParameter]; - code.openBlock(`def __init__(${constructorArguments.join(', ')}) -> None`); + openSignature(code, 'def', '__init__', constructorArguments, false, 'None'); this.emitConstructorDocstring(code); // Re-type struct arguments that were passed as "dict" @@ -971,23 +934,30 @@ class Struct extends BasePythonClassType { ...context, typeAnnotation: false, }); - code.line( - `if isinstance(${member.pythonName}, dict): ${member.pythonName} = ${typeName}(**${member.pythonName})`, - ); + code.openBlock(`if isinstance(${member.pythonName}, dict)`); + code.line(`${member.pythonName} = ${typeName}(**${member.pythonName})`); + code.closeBlock(); } // Required properties, those will always be put into the dict - code.line(`${implicitParameter}._values = {`); - for (const member of members.filter((m) => !m.optional)) { - code.line(` '${member.pythonName}': ${member.pythonName},`); - } - code.line('}'); + assignDictionary( + code, + `${implicitParameter}._values`, + members + .filter((m) => !m.optional) + .map( + (member) => + `${JSON.stringify(member.pythonName)}: ${member.pythonName}`, + ), + ); // Optional properties, will only be put into the dict if they're not None for (const member of members.filter((m) => m.optional)) { + code.openBlock(`if ${member.pythonName} is not None`); code.line( - `if ${member.pythonName} is not None: ${implicitParameter}._values["${member.pythonName}"] = ${member.pythonName}`, + `${implicitParameter}._values["${member.pythonName}"] = ${member.pythonName}`, ); + code.closeBlock(); } code.closeBlock(); @@ -1010,38 +980,50 @@ class Struct extends BasePythonClassType { context: EmitContext, ) { code.line('@builtins.property'); - code.openBlock( - `def ${member.pythonName}(self) -> ${member.typeAnnotation(context)}`, + openSignature( + code, + 'def', + member.pythonName, + ['self'], + true, + member.typeAnnotation(context), ); member.emitDocString(code); - code.line(`return self._values.get('${member.pythonName}')`); + code.line(`return self._values.get(${JSON.stringify(member.pythonName)})`); code.closeBlock(); } private emitMagicMethods(code: CodeMaker) { + code.line(); code.openBlock('def __eq__(self, rhs) -> bool'); code.line( 'return isinstance(rhs, self.__class__) and rhs._values == self._values', ); code.closeBlock(); + code.line(); code.openBlock('def __ne__(self, rhs) -> bool'); code.line('return not (rhs == self)'); code.closeBlock(); + code.line(); code.openBlock('def __repr__(self) -> str'); - code.line( - `return '${this.pythonName}(%s)' % ', '.join(k + '=' + repr(v) for k, v in self._values.items())`, - ); + code.indent(`return "${this.pythonName}(%s)" % ", ".join(`); + code.line('k + "=" + repr(v) for k, v in self._values.items()'); + code.unindent(')'); code.closeBlock(); } private propertyMap() { const ret = new Array(); for (const member of this.allMembers) { - ret.push(`'${member.pythonName}': '${member.jsiiName}'`); + ret.push( + `${JSON.stringify(member.pythonName)}: ${JSON.stringify( + member.jsiiName, + )}`, + ); } - return `{${ret.join(', ')}}`; + return ret; } } @@ -1074,7 +1056,7 @@ class StructField implements PythonBase { } public constructorDecl(context: EmitContext) { - const opt = this.optional ? '=None' : ''; + const opt = this.optional ? ' = None' : ''; return `${this.pythonName}: ${this.typeAnnotation(context)}${opt}`; } @@ -1193,9 +1175,9 @@ class Class extends BasePythonClassType implements ISortableType { ); } - code.openBlock( - `class ${this.getProxyClassName()}(${proxyBases.join(', ')})`, - ); + code.line(); + code.line(); + openSignature(code, 'class', this.getProxyClassName(), proxyBases); // Filter our list of members to *only* be abstract members, and not any // other types. @@ -1204,7 +1186,15 @@ class Class extends BasePythonClassType implements ISortableType { (m instanceof BaseMethod || m instanceof BaseProperty) && m.abstract, ); if (abstractMembers.length > 0) { + let first = true; for (const member of abstractMembers) { + if (this.separateMembers) { + if (first) { + first = false; + } else { + code.line(); + } + } member.emit(code, context, { renderAbstract: false }); } } else { @@ -1215,13 +1205,14 @@ class Class extends BasePythonClassType implements ISortableType { } } - protected emitPreamble(code: CodeMaker, _context: EmitContext) { - if (this.abstract) { + protected get emitPreamble() { + if (!this.abstract) return undefined; + return (code: CodeMaker, _context: EmitContext) => { code.line('@builtins.staticmethod'); code.openBlock('def __jsii_proxy_class__()'); code.line(`return ${this.getProxyClassName()}`); code.closeBlock(); - } + }; } protected getClassParams(context: EmitContext): string[] { @@ -1279,9 +1270,12 @@ class Property extends BaseProperty { } class Enum extends BasePythonClassType { + protected readonly emitPreamble = undefined; + protected readonly separateMembers = false; + public emit(code: CodeMaker, context: EmitContext) { context = { ...context, nestingScope: this.fqn! }; - code.line(`@jsii.enum(jsii_type="${this.fqn}")`); + emitList(code, '@jsii.enum(', [`jsii_type="${this.fqn}"`], ')'); return super.emit(code, context); } @@ -1385,14 +1379,16 @@ class PythonModule implements PythonType { this.emitDependencyImports(code); code.line(); - const params = [ - `"${this.assembly.name}"`, - `"${this.assembly.version}"`, - '__name__[0:-6]', // Removing the "._jsii" from the tail! - `"${this.assemblyFilename}"`, - ]; - code.line( - `__jsii_assembly__ = jsii.JSIIAssembly.load(${params.join(', ')})`, + emitList( + code, + '__jsii_assembly__ = jsii.JSIIAssembly.load(', + [ + JSON.stringify(this.assembly.name), + JSON.stringify(this.assembly.version), + '__name__[0:-6]', + `${JSON.stringify(this.assemblyFilename)}`, + ], + ')', ); } else { // Then we must import the ._jsii subpackage. @@ -1410,13 +1406,10 @@ class PythonModule implements PythonType { this.emitRequiredImports(code, context); } - code.line(); - if (this.members.length > 0) { - code.line(); - } - // Emit all of our members. for (const member of sortMembers(this.members, resolver)) { + code.line(); + code.line(); member.emit(code, context); } @@ -1427,6 +1420,10 @@ class PythonModule implements PythonType { } // Declare the list of "public" members this module exports + if (this.members.length > 0) { + code.line(); + } + code.line(); code.indent('__all__ = ['); for (const member of exportedMembers.sort()) { // Writing one by line might be _a lot_ of lines, but it'll make reviewing changes to the list easier. Trust me. @@ -1479,37 +1476,62 @@ class PythonModule implements PythonType { const requiredImports = this.requiredImports(context); const statements = Object.entries(requiredImports) .map(([sourcePackage, items]) => toImportStatements(sourcePackage, items)) - .reduce((acc, elt) => [...acc, ...elt], new Array()) + .reduce( + (acc, elt) => [...acc, ...elt], + new Array<{ emit: () => void; comparisonBase: string }>(), + ) .sort(importComparator); if (statements.length > 0) { code.line(); } for (const statement of statements) { - code.line(statement); + statement.emit(code); } function toImportStatements( sourcePkg: string, items: ReadonlySet, - ): string[] { - const result = new Array(); + ): Array<{ emit: (code: CodeMaker) => void; comparisonBase: string }> { + const result = new Array<{ + emit: (code: CodeMaker) => void; + comparisonBase: string; + }>(); if (items.has('')) { - result.push(`import ${sourcePkg}`); + result.push({ + comparisonBase: `import ${sourcePkg}`, + emit(code) { + code.line(this.comparisonBase); + }, + }); } - const pieceMeal = Array.from(items).filter((i) => i !== ''); + const pieceMeal = Array.from(items) + .filter((i) => i !== '') + .sort(); if (pieceMeal.length > 0) { - result.push(`from ${sourcePkg} import (${pieceMeal.join(', ')})`); + result.push({ + comparisonBase: `from ${sourcePkg} import`, + emit: (code) => + emitList(code, `from ${sourcePkg} import `, pieceMeal, '', { + ifMulti: ['(', ')'], + }), + }); } return result; } - function importComparator(left: string, right: string) { - if (left.startsWith('import') === right.startsWith('import')) { - return left.localeCompare(right); + function importComparator( + left: { comparisonBase: string }, + right: { comparisonBase: string }, + ) { + if ( + left.comparisonBase.startsWith('import') === + right.comparisonBase.startsWith('import') + ) { + return left.comparisonBase.localeCompare(right.comparisonBase); } // We want "from .foo import (...)" to be *after* "import bar" - return right.localeCompare(left); + return right.comparisonBase.localeCompare(left.comparisonBase); } } } @@ -1678,14 +1700,17 @@ class Package { code.line('import json'); code.line('import setuptools'); code.line(); - code.line('kwargs = json.loads("""'); + code.line('kwargs = json.loads('); + code.line(' """'); code.line(JSON.stringify(setupKwargs, null, 4)); - code.line('""")'); + code.line('"""'); + code.line(')'); code.line(); - code.openBlock("with open('README.md') as fp"); - code.line("kwargs['long_description'] = fp.read()"); + code.openBlock('with open("README.md") as fp'); + code.line('kwargs["long_description"] = fp.read()'); code.closeBlock(); code.line(); + code.line(); code.line('setuptools.setup(**kwargs)'); code.closeFile('setup.py'); @@ -1850,7 +1875,7 @@ class PythonGenerator extends Generator { super(options); this.code.openBlockFormatter = (s) => `${s}:`; - this.code.closeBlockFormatter = (_s) => ''; + this.code.closeBlockFormatter = (_s) => false; this.types = new Map(); } @@ -1862,6 +1887,7 @@ class PythonGenerator extends Generator { options: { arguments?: DocumentableArgument[]; documentableItem?: string; + trailingNewLine?: boolean; } = {}, ) { if ((!docs || Object.keys(docs).length === 0) && !options.arguments) { @@ -1973,17 +1999,19 @@ class PythonGenerator extends Generator { if (lines.length === 1) { code.line(`"""${lines[0]}"""`); - return; - } + } else { + code.line(`"""${lines[0]}`); + lines.splice(0, 1); - code.line(`"""${lines[0]}`); - lines.splice(0, 1); + for (const line of lines) { + code.line(line); + } - for (const line of lines) { - code.line(line); + code.line('"""'); + } + if (options.trailingNewLine) { + code.line(); } - - code.line('"""'); } public convertExample(example: string): string { @@ -2448,26 +2476,204 @@ function slugifyAsNeeded(name: string, inUse: readonly string[]): string { return name; } -async function lock(path: string, opts: lockfile.Options = { stale: 60_000 }) { - return new Promise((ok, ko) => - lockfile.lock(path, opts, (error) => { - if (error != null) { - ko(error); - } else { - ok(); - } - }), - ); +//////////////////////////////////////////////////////////////////////////////// +// BEHOLD: Helpers to output code that looks like what Black would format into... +// +// @see https://black.readthedocs.io/en/stable/the_black_code_style.html + +const TARGET_LINE_LENGTH = 88; + +function openSignature( + code: CodeMaker, + keyword: 'class', + name: string, + params: readonly string[], +): void; +function openSignature( + code: CodeMaker, + keyword: 'def', + name: string, + params: readonly string[], + trailingComma: boolean, + returnType: string, +): void; +function openSignature( + code: CodeMaker, + keyword: 'class' | 'def', + name: string, + params: readonly string[], + trailingComma = false, + returnType?: string, +) { + const prefix = `${keyword} ${name}`; + const suffix = returnType ? ` -> ${returnType}` : ''; + if (params.length === 0) { + code.openBlock(`${prefix}${returnType ? '()' : ''}${suffix}`); + return; + } + + const join = ', '; + const { elementsSize, joinSize } = totalSizeOf(params, join); + + if ( + TARGET_LINE_LENGTH > + code.currentIndentLength + + prefix.length + + elementsSize + + joinSize + + suffix.length + + 2 + ) { + code.openBlock(`${prefix}(${params.join(join)})${suffix}`); + return; + } + + code.indent(`${prefix}(`); + if ( + TARGET_LINE_LENGTH > + code.currentIndentLength + elementsSize + joinSize + (trailingComma ? 1 : 0) + ) { + code.line(`${params.join(join)}${trailingComma ? ',' : ''}`); + } else { + for (const param of params) { + code.line(`${param},`); + } + } + code.unindent(false); + code.openBlock(`)${suffix}`); } -async function unlock(path: string) { - return new Promise((ok, ko) => - lockfile.unlock(path, (error) => { - if (error != null) { - ko(error); - } else { - ok(); +function assignCallResult( + code: CodeMaker, + variable: string, + funct: string, + params: readonly string[], +) { + const prefix = `${variable} = ${funct}(`; + const suffix = ')'; + + if (params.length === 0) { + code.line(`${prefix}${suffix}`); + return; + } + + const join = ', '; + const { elementsSize, joinSize } = totalSizeOf(params, join); + + if ( + TARGET_LINE_LENGTH > + code.currentIndentLength + + prefix.length + + elementsSize + + joinSize + + suffix.length + ) { + code.line(`${prefix}${params.join(join)}${suffix}`); + return; + } + + code.indent(prefix); + if (TARGET_LINE_LENGTH > code.currentIndentLength + elementsSize + joinSize) { + code.line(params.join(join)); + } else { + for (const param of params) { + code.line(`${param},`); + } + } + code.unindent(suffix); +} + +function assignDictionary( + code: CodeMaker, + variable: string, + elements: readonly string[], + trailing?: string, + compact = false, +): void { + const space = compact ? '' : ' '; + + const prefix = `${variable}${space}=${space}{`; + const suffix = `}${trailing ?? ''}`; + + if (elements.length === 0) { + code.line(`${prefix}${suffix}`); + return; + } + + if (compact) { + const join = ', '; + const { elementsSize, joinSize } = totalSizeOf(elements, join); + if ( + TARGET_LINE_LENGTH > + prefix.length + + code.currentIndentLength + + elementsSize + + joinSize + + suffix.length + ) { + code.line(`${prefix}${elements.join(join)}${suffix}`); + return; + } + } + + code.indent(prefix); + for (const elt of elements) { + code.line(`${elt},`); + } + code.unindent(suffix); +} + +function emitList( + code: CodeMaker, + prefix: string, + elements: readonly string[], + suffix: string, + opts?: { ifMulti: [string, string] }, +) { + if (elements.length === 0) { + code.line(`${prefix}${suffix}`); + return; + } + + const join = ', '; + const { elementsSize, joinSize } = totalSizeOf(elements, join); + if ( + TARGET_LINE_LENGTH > + code.currentIndentLength + + prefix.length + + elementsSize + + joinSize + + suffix.length + ) { + code.line(`${prefix}${elements.join(join)}${suffix}`); + return; + } + + const [before, after] = opts?.ifMulti ?? ['', '']; + + code.indent(`${prefix}${before}`); + if (elements.length === 1) { + code.line(elements[0]); + } else { + if ( + TARGET_LINE_LENGTH > + code.currentIndentLength + elementsSize + joinSize + ) { + code.line(elements.join(join)); + } else { + for (const elt of elements) { + code.line(`${elt},`); } - }), - ); + } + } + code.unindent(`${after}${suffix}`); +} + +function totalSizeOf(strings: readonly string[], join: string) { + return { + elementsSize: strings + .map((str) => str.length) + .reduce((acc, elt) => acc + elt, 0), + joinSize: strings.length > 1 ? join.length * (strings.length - 1) : 0, + }; } diff --git a/packages/jsii-pacmak/package.json b/packages/jsii-pacmak/package.json index a71475f3e1..2b7ba113a3 100644 --- a/packages/jsii-pacmak/package.json +++ b/packages/jsii-pacmak/package.json @@ -43,7 +43,6 @@ "fs-extra": "^9.0.1", "jsii-reflect": "^0.0.0", "jsii-rosetta": "^0.0.0", - "lockfile": "^1.0.4", "semver": "^7.3.2", "spdx-license-list": "^6.2.0", "xmlbuilder": "^15.1.1", @@ -57,7 +56,6 @@ "@types/commonmark": "^0.27.4", "@types/fs-extra": "^8.1.1", "@types/jest": "^26.0.9", - "@types/lockfile": "^1.0.1", "@types/mock-fs": "^4.10.0", "@types/node": "^10.17.28", "@types/semver": "^7.3.1", @@ -70,6 +68,7 @@ "jsii-calc": "^0.0.0", "mock-fs": "^4.12.0", "prettier": "^2.0.5", + "ts-jest": "^26.1.4", "typescript": "~3.9.7" }, "keywords": [ @@ -89,7 +88,10 @@ "errorOnDeprecated": true, "testEnvironment": "node", "testMatch": [ - "**/?(*.)+(spec|test).js" - ] + "**/?(*.)+(spec|test).ts" + ], + "transform": { + "\\.tsx?$": "ts-jest" + } } } diff --git a/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.js.snap b/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap similarity index 99% rename from packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.js.snap rename to packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap index 204f67e395..96df49deac 100644 --- a/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.js.snap +++ b/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap @@ -56971,9 +56971,7 @@ class AllTypes(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.AllTypes\\"): @jsii.member(jsii_name=\\"unionMapProperty\\") def union_map_property( self, - ) -> typing.Mapping[ - str, typing.Union[str, jsii.Number, scope.jsii_calc_lib.Number] - ]: + ) -> typing.Mapping[str, typing.Union[str, jsii.Number, scope.jsii_calc_lib.Number]]: \\"\\"\\" stability :stability: experimental @@ -56983,9 +56981,7 @@ class AllTypes(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.AllTypes\\"): @union_map_property.setter def union_map_property( self, - value: typing.Mapping[ - str, typing.Union[str, jsii.Number, scope.jsii_calc_lib.Number] - ], + value: typing.Mapping[str, typing.Union[str, jsii.Number, scope.jsii_calc_lib.Number]], ) -> None: jsii.set(self, \\"unionMapProperty\\", value) @@ -57764,7 +57760,8 @@ class ClassWithJavaReservedWords( class ClassWithMutableObjectLiteralProperty( - metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.ClassWithMutableObjectLiteralProperty\\" + metaclass=jsii.JSIIMeta, + jsii_type=\\"jsii-calc.ClassWithMutableObjectLiteralProperty\\", ): \\"\\"\\" stability @@ -57825,12 +57822,7 @@ class ConfusingToJackson( @jsii.member(jsii_name=\\"unionProperty\\") def union_property( self, - ) -> typing.Optional[ - typing.Union[ - scope.jsii_calc_lib.IFriendly, - typing.List[typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"]], - ] - ]: + ) -> typing.Optional[typing.Union[scope.jsii_calc_lib.IFriendly, typing.List[typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"]]]]: \\"\\"\\" stability :stability: experimental @@ -57840,14 +57832,7 @@ class ConfusingToJackson( @union_property.setter def union_property( self, - value: typing.Optional[ - typing.Union[ - scope.jsii_calc_lib.IFriendly, - typing.List[ - typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"] - ], - ] - ], + value: typing.Optional[typing.Union[scope.jsii_calc_lib.IFriendly, typing.List[typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"]]]], ) -> None: jsii.set(self, \\"unionProperty\\", value) @@ -57861,14 +57846,7 @@ class ConfusingToJacksonStruct: def __init__( self, *, - union_property: typing.Optional[ - typing.Union[ - scope.jsii_calc_lib.IFriendly, - typing.List[ - typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"] - ], - ] - ] = None, + union_property: typing.Optional[typing.Union[scope.jsii_calc_lib.IFriendly, typing.List[typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"]]]] = None, ) -> None: \\"\\"\\" :param union_property: @@ -57883,12 +57861,7 @@ class ConfusingToJacksonStruct: @builtins.property def union_property( self, - ) -> typing.Optional[ - typing.Union[ - scope.jsii_calc_lib.IFriendly, - typing.List[typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"]], - ] - ]: + ) -> typing.Optional[typing.Union[scope.jsii_calc_lib.IFriendly, typing.List[typing.Union[scope.jsii_calc_lib.IFriendly, \\"AbstractClass\\"]]]]: \\"\\"\\" stability :stability: experimental @@ -58501,9 +58474,7 @@ class DerivedStruct(scope.jsii_calc_lib.MyFirstStruct): another_required: datetime.datetime, bool: bool, non_primitive: \\"DoubleTrouble\\", - another_optional: typing.Optional[ - typing.Mapping[str, scope.jsii_calc_lib.Value] - ] = None, + another_optional: typing.Optional[typing.Mapping[str, scope.jsii_calc_lib.Value]] = None, optional_any: typing.Any = None, optional_array: typing.Optional[typing.List[str]] = None, ) -> None: @@ -58772,8 +58743,7 @@ class DiamondInheritanceSecondMidLevelStruct(DiamondInheritanceBaseLevelStruct): @jsii.data_type( jsii_type=\\"jsii-calc.DiamondInheritanceTopLevelStruct\\", jsii_struct_bases=[ - DiamondInheritanceFirstMidLevelStruct, - DiamondInheritanceSecondMidLevelStruct, + DiamondInheritanceFirstMidLevelStruct, DiamondInheritanceSecondMidLevelStruct ], name_mapping={ \\"base_level_property\\": \\"baseLevelProperty\\", @@ -58962,9 +58932,7 @@ class DoNotRecognizeAnyAsOptional( stability :stability: experimental \\"\\"\\" - return jsii.invoke( - self, \\"method\\", [_required_any, _optional_any, _optional_string] - ) + return jsii.invoke(self, \\"method\\", [_required_any, _optional_any, _optional_string]) class DocumentedClass(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.DocumentedClass\\"): @@ -59495,9 +59463,7 @@ class GiveMeStructs(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.GiveMeStruct another_required: datetime.datetime, bool: bool, non_primitive: \\"DoubleTrouble\\", - another_optional: typing.Optional[ - typing.Mapping[str, scope.jsii_calc_lib.Value] - ] = None, + another_optional: typing.Optional[typing.Mapping[str, scope.jsii_calc_lib.Value]] = None, optional_any: typing.Any = None, optional_array: typing.Optional[typing.List[str]] = None, anumber: jsii.Number, @@ -59540,9 +59506,7 @@ class GiveMeStructs(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.GiveMeStruct another_required: datetime.datetime, bool: bool, non_primitive: \\"DoubleTrouble\\", - another_optional: typing.Optional[ - typing.Mapping[str, scope.jsii_calc_lib.Value] - ] = None, + another_optional: typing.Optional[typing.Mapping[str, scope.jsii_calc_lib.Value]] = None, optional_any: typing.Any = None, optional_array: typing.Optional[typing.List[str]] = None, anumber: jsii.Number, @@ -59612,7 +59576,9 @@ class GiveMeStructs(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.GiveMeStruct @jsii.data_type( - jsii_type=\\"jsii-calc.Greetee\\", jsii_struct_bases=[], name_mapping={\\"name\\": \\"name\\"} + jsii_type=\\"jsii-calc.Greetee\\", + jsii_struct_bases=[], + name_mapping={\\"name\\": \\"name\\"}, ) class Greetee: def __init__(self, *, name: typing.Optional[str] = None) -> None: @@ -60662,8 +60628,6 @@ class IJsii487External(jsii.compat.Protocol): def __jsii_proxy_class__(): return _IJsii487ExternalProxy - pass - class _IJsii487ExternalProxy: \\"\\"\\" @@ -60686,8 +60650,6 @@ class IJsii487External2(jsii.compat.Protocol): def __jsii_proxy_class__(): return _IJsii487External2Proxy - pass - class _IJsii487External2Proxy: \\"\\"\\" @@ -60710,8 +60672,6 @@ class IJsii496(jsii.compat.Protocol): def __jsii_proxy_class__(): return _IJsii496Proxy - pass - class _IJsii496Proxy: \\"\\"\\" @@ -62718,9 +62678,7 @@ class NullShouldBeTreatedAsUndefined( def give_me_undefined_inside_an_object( self, *, - array_with_three_elements_and_undefined_as_second_argument: typing.List[ - typing.Any - ], + array_with_three_elements_and_undefined_as_second_argument: typing.List[typing.Any], this_should_be_undefined: typing.Any = None, ) -> None: \\"\\"\\" @@ -62771,9 +62729,7 @@ class NullShouldBeTreatedAsUndefinedData: def __init__( self, *, - array_with_three_elements_and_undefined_as_second_argument: typing.List[ - typing.Any - ], + array_with_three_elements_and_undefined_as_second_argument: typing.List[typing.Any], this_should_be_undefined: typing.Any = None, ) -> None: \\"\\"\\" @@ -62797,9 +62753,7 @@ class NullShouldBeTreatedAsUndefinedData: stability :stability: experimental \\"\\"\\" - return self._values.get( - \\"array_with_three_elements_and_undefined_as_second_argument\\" - ) + return self._values.get(\\"array_with_three_elements_and_undefined_as_second_argument\\") @builtins.property def this_should_be_undefined(self) -> typing.Any: @@ -63269,7 +63223,10 @@ class PartiallyInitializedThisConsumer( @jsii.member(jsii_name=\\"consumePartiallyInitializedThis\\") @abc.abstractmethod def consume_partially_initialized_this( - self, obj: \\"ConstructorPassesThisOut\\", dt: datetime.datetime, ev: \\"AllTypesEnum\\" + self, + obj: \\"ConstructorPassesThisOut\\", + dt: datetime.datetime, + ev: \\"AllTypesEnum\\", ) -> str: \\"\\"\\" :param obj: - @@ -63285,7 +63242,10 @@ class PartiallyInitializedThisConsumer( class _PartiallyInitializedThisConsumerProxy(PartiallyInitializedThisConsumer): @jsii.member(jsii_name=\\"consumePartiallyInitializedThis\\") def consume_partially_initialized_this( - self, obj: \\"ConstructorPassesThisOut\\", dt: datetime.datetime, ev: \\"AllTypesEnum\\" + self, + obj: \\"ConstructorPassesThisOut\\", + dt: datetime.datetime, + ev: \\"AllTypesEnum\\", ) -> str: \\"\\"\\" :param obj: - @@ -63795,7 +63755,10 @@ class ReturnsPrivateImplementationOfInterface( ) class RootStruct: def __init__( - self, *, string_prop: str, nested_struct: typing.Optional[\\"NestedStruct\\"] = None + self, + *, + string_prop: str, + nested_struct: typing.Optional[\\"NestedStruct\\"] = None, ) -> None: \\"\\"\\"This is here to check that we can pass a nested struct into a kwargs by specifying it as an in-line dictionary. @@ -66093,8 +66056,6 @@ class IFriendlyRandomGenerator( def __jsii_proxy_class__(): return _IFriendlyRandomGeneratorProxy - pass - class _IFriendlyRandomGeneratorProxy( jsii.proxy_for(IRandomNumberGenerator), @@ -67241,10 +67202,10 @@ from .._jsii import * from .. import AllTypes as _AllTypes_b08307c5 from .child import ( - SomeStruct as _SomeStruct_91627123, - SomeEnum as _SomeEnum_b2e41d92, Awesomeness as _Awesomeness_d37a24df, Goodness as _Goodness_2df26737, + SomeEnum as _SomeEnum_b2e41d92, + SomeStruct as _SomeStruct_91627123, ) from .nested_submodule.deeply_nested import INamespaced as _INamespaced_e2f386ad @@ -67665,7 +67626,9 @@ import publication from ..._jsii import * -from ..child import KwargsProps as _KwargsProps_c7855dcf, SomeEnum as _SomeEnum_b2e41d92 +from ..child import ( + KwargsProps as _KwargsProps_c7855dcf, SomeEnum as _SomeEnum_b2e41d92 +) class Kwargs(metaclass=jsii.JSIIMeta, jsii_type=\\"jsii-calc.submodule.isolated.Kwargs\\"): diff --git a/packages/jsii-pacmak/test/jsii-pacmak.test.ts b/packages/jsii-pacmak/test/jsii-pacmak.test.ts index 97ebd521cd..a83ab003b0 100644 --- a/packages/jsii-pacmak/test/jsii-pacmak.test.ts +++ b/packages/jsii-pacmak/test/jsii-pacmak.test.ts @@ -134,7 +134,7 @@ function runPacmak(root: string, outdir: string): void { if (result.status !== 0) { console.error(`#### PACMAK STDOUT:\n${result.stdout.toString('utf-8')}`); - console.error(`#### PACMAK STDERR:\n${result.stdout.toString('utf-8')}`); + console.error(`#### PACMAK STDERR:\n${result.stderr.toString('utf-8')}`); } expect(result.signal).toBeNull(); diff --git a/packages/jsii-pacmak/test/targets/python.test.ts b/packages/jsii-pacmak/test/targets/python.test.ts deleted file mode 100644 index 2009f4195f..0000000000 --- a/packages/jsii-pacmak/test/targets/python.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -import * as util from '../../lib/util'; -import * as os from 'os'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import Python from '../../lib/targets/python'; -import { Assembly } from 'jsii-reflect'; -import { Rosetta } from 'jsii-rosetta'; - -describe('python', () => { - describe('blackPath', () => { - const shellMock = jest.fn(); - const homedirMock = jest.fn(); - let homedir: string; - let python: Python; - - beforeEach((done) => { - // eslint-disable-next-line no-import-assign - Object.defineProperty(util, 'shell', { value: shellMock }); - // eslint-disable-next-line no-import-assign - Object.defineProperty(os, 'homedir', { value: homedirMock }); - homedir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsii-pacmak-black-')); - homedirMock.mockImplementation(() => homedir); - python = new Python({ - targetName: 'python', - packageDir: '/dir', - assembly: {} as Assembly, - rosetta: new Rosetta(), - arguments: {}, - }); - - done(); - }); - - afterEach((done) => { - shellMock.mockClear(); - homedirMock.mockClear(); - fs.removeSync(homedir); - - done(); - }); - - test('black is installed globally', async () => { - let badShellCommand: string | undefined; - shellMock.mockImplementation((cmd: string, args: string[], _) => { - return new Promise((ok, ko) => { - if (cmd === 'which' && args[0] === 'black') { - ok('/path/to/black'); - } else { - badShellCommand = `Unexpected call to shell [${cmd} ${args.join( - ' ', - )}]`; - ko(new Error(badShellCommand)); - } - }); - }); - - const path = await (python as any).blackPath(); // call private method blackPath() - expect(badShellCommand).toBeUndefined(); - expect(path).toBe('black'); - }); - - test('black is installed if not found globally', async () => { - shellMock.mockImplementation((cmd: string, args: string[], _) => { - return new Promise((ok, ko) => { - if (cmd === 'which' && args[0] === 'black') { - ko(new Error('black not found')); - } else if ( - /pip.?$/.test(cmd) && - args[0] === 'show' && - args[1] === 'black' - ) { - ko(new Error()); - } else if ( - /pip.?$/.test(cmd) && - args[0] === 'install' && - args[1] === '--no-input' && - args[2] === 'black' - ) { - fs.mkdirpSync( - path.join( - homedir, - '.jsii-cache', - 'python-black', - 'venv', - process.platform === 'win32' ? 'Scripts' : 'bin', - `black${process.platform === 'win32' ? '.exe' : ''}`, - ), - ); - ok(); - } else { - ok(); - } - }); - }); - - const blackPath = await (python as any).blackPath(); // call private method blackPath() - expect(blackPath).toBe( - path.join( - homedir, - '.jsii-cache', - 'python-black', - 'venv', - process.platform === 'win32' ? 'Scripts' : 'bin', - `black${process.platform === 'win32' ? '.exe' : ''}`, - ), - ); - }); - - test('local cache is reused', async () => { - let installCount = 0; - shellMock.mockImplementation((cmd: string, args: string[], _) => { - return new Promise((ok, ko) => { - if (cmd === 'which' && args[0] === 'black') { - ko(new Error('black not found')); - } else if ( - /pip.?$/.test(cmd) && - args[0] === 'show' && - args[1] === 'black' - ) { - ko(new Error()); - } else if ( - /pip.?$/.test(cmd) && - args[0] === 'install' && - args[1] === '--no-input' && - args[2] === 'black' - ) { - installCount++; - fs.mkdirpSync( - path.join( - homedir, - '.jsii-cache', - 'python-black', - 'venv', - process.platform === 'win32' ? 'Scripts' : 'bin', - `black${process.platform === 'win32' ? '.bat' : ''}`, - ), - ); - ok(); - } else { - ok(); - } - }); - }); - - await (python as any).blackPath(); - await (python as any).blackPath(); - await (python as any).blackPath(); - expect(installCount).toEqual(1); - }); - }); -}); diff --git a/yarn.lock b/yarn.lock index 72e242a473..965e6ba062 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1552,11 +1552,6 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/lockfile@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/lockfile/-/lockfile-1.0.1.tgz#434a3455e89843312f01976e010c60f1bcbd56f7" - integrity sha512-65WZedEm4AnOsBDdsapJJG42MhROu3n4aSSiu87JXF/pSdlubxZxp3S1yz3kTfkJ2KBPud4CpjoHVAptOm9Zmw== - "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -2478,6 +2473,13 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -2490,7 +2492,7 @@ btoa-lite@^1.0.0: resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= -buffer-from@^1.0.0: +buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -4160,7 +4162,7 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5769,7 +5771,7 @@ jest-snapshot@^26.2.2: pretty-format "^26.2.0" semver "^7.3.2" -jest-util@^26.2.0: +jest-util@26.x, jest-util@^26.2.0: version "26.2.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.2.0.tgz#0597d2a27c559340957609f106c408c17c1d88ac" integrity sha512-YmDwJxLZ1kFxpxPfhSJ0rIkiZOM0PQbRcfH0TzJOhqCisCAsI1WcmoQqO83My9xeVA2k4n+rzg2UuexVKzPpig== @@ -5911,6 +5913,13 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@2.x, json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -5918,13 +5927,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -6133,13 +6135,6 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lockfile@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" - integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== - dependencies: - signal-exit "^3.0.2" - lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -6160,6 +6155,11 @@ lodash.ismatch@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" @@ -6253,7 +6253,7 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@^1.1.1: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -6568,7 +6568,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*, mkdirp@^1.0.3: +mkdirp@*, mkdirp@1.x, mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -8101,16 +8101,16 @@ semver-intersect@^1.4.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.1.1, semver@^7.2.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - serialize-javascript@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea" @@ -8986,6 +8986,22 @@ trim-off-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= +ts-jest@^26.1.4: + version "26.1.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.4.tgz#87d41a96016a8efe4b8cc14501d3785459af6fa6" + integrity sha512-Nd7diUX6NZWfWq6FYyvcIPR/c7GbEF75fH1R6coOp3fbNzbRJBZZAn0ueVS0r8r9ral1VcrpneAFAwB3TsVS1Q== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "26.x" + json5 "2.x" + lodash.memoize "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "18.x" + ts-node@^8.10.2: version "8.10.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" @@ -9673,6 +9689,14 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yargs-parser@18.x, yargs-parser@^18.1.2, yargs-parser@^18.1.3: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" @@ -9689,14 +9713,6 @@ yargs-parser@^15.0.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.2, yargs-parser@^18.1.3: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"