Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
public toNativeFqn(fqn: string): string {
const type = this.findType(fqn);
let typeName = '';
switch (type.kind) {
case spec.TypeKind.Interface:
typeName = this.nameutils.convertInterfaceName(type);
break;
case spec.TypeKind.Class:
typeName = this.nameutils.convertClassName(type as spec.ClassType);
break;
case spec.TypeKind.Enum:
typeName = this.nameutils.convertTypeName(type.name);
break;
default:
throw new Error(`Unknown type: ${type}`);
}
const [mod] = fqn.split('.');
const depMod = this.findModule(mod);
const dotnetNamespace = depMod.targets?.dotnet?.namespace;
if (!dotnetNamespace) {
throw new Error('The module does not have a dotnet.namespace setting');
}
if (type.namespace) {
// If the type is declared in an additional namespace.
public toNativeFqn(fqn: string): string {
const type = this.findType(fqn);
let typeName = '';
switch (type.kind) {
case spec.TypeKind.Interface:
typeName = this.nameutils.convertInterfaceName(type);
break;
case spec.TypeKind.Class:
typeName = this.nameutils.convertClassName(type as spec.ClassType);
break;
case spec.TypeKind.Enum:
typeName = this.nameutils.convertTypeName(type.name);
break;
default:
throw new Error(`Unknown type: ${type}`);
}
const [mod] = fqn.split('.');
const depMod = this.findModule(mod);
const dotnetNamespace = depMod.targets?.dotnet?.namespace;
if (!dotnetNamespace) {
throw new Error('The module does not have a dotnet.namespace setting');
}
if (type.namespace) {
// If the type is declared in an additional namespace.
const namespaceFqn = `${this.assembly.name}.${type.namespace}`;
const associatedNamespace = this.assembly.types?.[namespaceFqn];
if (associatedNamespace) {
public static toNativeReference(type: spec.Type) {
const [, ...name] = type.fqn.split('.');
const resolvedName = name.join('.');
const result: { typescript: string, javascript?: string } = {
typescript: `import { ${resolvedName} } from '${type.assembly}';`
};
if (!spec.isInterfaceType(type)) {
result.javascript = `const { ${resolvedName} } = require('${type.assembly}');`;
} else {
result.javascript = `// ${resolvedName} is an interface`;
}
return result;
}
if (await fs.pathExists(npmIgnorePath)) {
lines = (await fs.readFile(npmIgnorePath)).toString().split('\n');
}
// if this is a fresh .npmignore, we can be a bit more opinionated
// otherwise, we add just add stuff that's critical
if (lines.length === 0) {
excludePattern('Exclude typescript source and config', '*.ts', 'tsconfig.json');
includePattern('Include javascript files and typescript declarations', '*.js', '*.d.ts');
}
if (excludeOutdir) {
excludePattern('Exclude jsii outdir', path.relative(packageDir, excludeOutdir));
}
includePattern('Include .jsii', spec.SPEC_FILE_NAME);
if (modified) {
await fs.writeFile(npmIgnorePath, `${lines.join('\n')}\n`);
logging.info('Updated .npmignore');
}
function includePattern(comment: string, ...patterns: string[]) {
excludePattern(comment, ...patterns.map(p => `!${p}`));
}
function excludePattern(comment: string, ...patterns: string[]) {
let first = true;
for (const pattern of patterns) {
if (lines.includes(pattern)) {
return; // already in .npmignore
}
LOG.debug(`Base class of ${colors.green(jsiiType.fqn)} named ${colors.green(base.symbol.name)} is not exported, erasing it...`);
erasedBases.push(base);
base = (base.getBaseTypes() ?? [])[0];
}
if (!base) {
// There is no exported base class to be found, pretend this class has no base class.
continue;
}
// eslint-disable-next-line no-await-in-loop
const ref = await this._typeReference(base, type.symbol.valueDeclaration);
if (!spec.isNamedTypeReference(ref)) {
this._diagnostic(base.symbol.valueDeclaration,
ts.DiagnosticCategory.Error,
`Base type of ${jsiiType.fqn} is not a named type (${spec.describeTypeReference(ref)})`);
continue;
}
this._deferUntilTypesAvailable(fqn, [ref], base.symbol.valueDeclaration, (deref) => {
if (!spec.isClassType(deref)) {
this._diagnostic(base.symbol.valueDeclaration,
ts.DiagnosticCategory.Error,
`Base type of ${jsiiType.fqn} is not a class (${spec.describeTypeReference(ref)})`);
}
});
jsiiType.base = ref.fqn;
}
//
// base interfaces ("implements foo")
// collect all "implements" declarations from the current type and all
diagnostic(ts.DiagnosticCategory.Error,
`${label} changes the return type when ${action} (expected ${expType}, found ${actType})`);
}
const expectedParams = expected.parameters ?? [];
const actualParams = actual.parameters ?? [];
if (expectedParams.length !== actualParams.length) {
diagnostic(ts.DiagnosticCategory.Error,
`${label} changes argument count when ${action} (expected ${expectedParams.length}, found ${actualParams.length})`);
return;
}
for (let i = 0 ; i < expectedParams.length ; i++) {
const expParam = expectedParams[i];
const actParam = actualParams[i];
if (!deepEqual(expParam.type, actParam.type)) {
const expType = spec.describeTypeReference(expParam.type);
const actType = spec.describeTypeReference(actParam.type);
diagnostic(ts.DiagnosticCategory.Error,
`${label} changes type of argument ${actParam.name} when ${action} (expected ${expType}, found ${actType}`);
}
// Not-ing those to force the values to a strictly boolean context (they're optional, undefined means false)
if (expParam.variadic !== actParam.variadic) {
diagnostic(ts.DiagnosticCategory.Error,
`${label} changes the variadicity of parameter ${actParam.name} when ${action} (expected ${!!expParam.variadic}, found ${!!actParam.variadic})`);
}
if (expParam.optional !== actParam.optional) {
diagnostic(ts.DiagnosticCategory.Error,
`${label} changes the optionality of paramerter ${actParam.name} when ${action} (expected ${!!expParam.optional}, found ${!!actParam.optional})`);
}
}
}
const params: spec.Parameter[] = method?.parameters ?? [];
// error if args > params
if (args.length > params.length && !(method && method.variadic)) {
throw new Error(`Too many arguments (method accepts ${params.length} parameters, got ${args.length} arguments)`);
}
for (let i = 0; i < params.length; ++i) {
const param = params[i];
const arg = args[i];
if (param.variadic) {
if (params.length <= i) { return; } // No vararg was provided
for (let j = i ; j < params.length ; j++) {
if (!param.optional && params[j] === undefined) {
throw new Error(`Unexpected 'undefined' value at index ${j - i} of variadic argument '${param.name}' of type '${spec.describeTypeReference(param.type)}'`);
}
}
} else if (!param.optional && arg === undefined) {
throw new Error(`Not enough arguments. Missing argument for the required parameter '${param.name}' of type '${spec.describeTypeReference(param.type)}'`);
}
}
}
function _inehritanceDoesNotChangeContracts(validator: Validator, assembly: spec.Assembly, diagnostic: DiagnosticEmitter) {
for (const type of _allTypes(assembly)) {
if (spec.isClassType(type)) {
for (const method of type.methods ?? []) {
_validateMethodOverride(method, type);
}
for (const property of type.properties ?? []) {
_validatePropertyOverride(property, type);
}
}
if (spec.isClassOrInterfaceType(type) && (type.interfaces?.length ?? 0) > 0) {
for (const method of type.methods ?? []) {
// Overrides "win" over implementations
if (method.overrides) { continue; }
_validateMethodImplementation(method, type);
}
for (const property of type.properties ?? []) {
_validatePropertyImplementation(property, type);
}
function isAssignable(actualTypeFqn: string, requiredType: spec.NamedTypeReference, lookup: TypeLookup): boolean {
// The empty object is assignable to everything
if (actualTypeFqn === EMPTY_OBJECT_FQN) { return true; }
if (requiredType.fqn === actualTypeFqn) {
return true;
}
const actualType = lookup(actualTypeFqn);
if (spec.isClassType(actualType)) {
if (actualType.base && isAssignable(actualType.base, requiredType, lookup)) {
return true;
}
}
if (spec.isClassOrInterfaceType(actualType) && actualType.interfaces) {
return actualType.interfaces.find(iface => isAssignable(iface, requiredType, lookup)) != null;
}
return false;
}
function _validateMethodImplementation(method: spec.Method, type: spec.ClassType | spec.InterfaceType): boolean {
if (!type.interfaces) {
// Abstract classes may not directly implement all members, need to check their supertypes...
if (spec.isClassType(type) && type.base && type.abstract) {
return _validateMethodImplementation(method, _dereference(type.base, assembly, validator) as spec.ClassType);
}
return false;
}
for (const iface of type.interfaces) {
const ifaceType = _dereference(iface, assembly, validator) as spec.InterfaceType;
const implemented = (ifaceType.methods ?? []).find(m => m.name === method.name);
if (implemented) {
_assertSignaturesMatch(implemented, method, `${type.fqn}#${method.name}`, `implementing ${ifaceType.fqn}`);
method.overrides = iface;
return true;
}
if (_validateMethodImplementation(method, ifaceType)) {
return true;
}
}