ts-morph#ImportSpecifierStructure TypeScript Examples

The following examples show how to use ts-morph#ImportSpecifierStructure. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: import-declaration-map.ts    From prisma-nestjs-graphql with MIT License 6 votes vote down vote up
create(args: {
    name: string;
    from: string;
    defaultImport?: string | true;
    namespaceImport?: string;
    namedImport?: boolean;
  }) {
    const { from, defaultImport, namespaceImport, namedImport } = args;
    let name = args.name;
    const value = {
      moduleSpecifier: from,
      namedImports: [] as OptionalKind<ImportSpecifierStructure>[],
      defaultImport: undefined as string | undefined,
      namespaceImport: undefined as string | undefined,
    };
    if (namedImport === true && namespaceImport) {
      value.namedImports = [{ name: namespaceImport }];
      name = namespaceImport;
    } else if (defaultImport) {
      value.defaultImport = defaultImport === true ? name : defaultImport;
      name = value.defaultImport;
    } else if (namespaceImport) {
      value.namespaceImport = namespaceImport;
      name = namespaceImport;
    } else {
      value.namedImports = [{ name }];
    }
    this.add(name, value);
  }
Example #2
Source File: generate.spec.ts    From prisma-nestjs-graphql with MIT License 6 votes vote down vote up
setSourceFile = (name: string) => {
  sourceFile = project.getSourceFileOrThrow(s => s.getFilePath().endsWith(name));
  sourceText = sourceFile.getText();
  classFile = sourceFile.getClass(() => true)!;
  importDeclarations = sourceFile.getImportDeclarations().map(d => d.getStructure());
  imports = importDeclarations.flatMap(d =>
    (d.namedImports as ImportSpecifierStructure[]).map(x => ({
      name: x.name,
      specifier: d.moduleSpecifier,
    })),
  );
}
Example #3
Source File: test.spec.ts    From prisma-nestjs-graphql with MIT License 6 votes vote down vote up
setSourceFile = (name: string) => {
  sourceFile = project.getSourceFile(s => s.getFilePath().endsWith(name))!;
  classFile = sourceFile.getClass(() => true)!;
  sourceText = sourceFile.getText();
  importDeclarations = sourceFile.getImportDeclarations().map(d => d.getStructure());
  imports = importDeclarations.flatMap(d =>
    (d.namedImports as ImportSpecifierStructure[]).map(x => ({
      name: x.name,
      specifier: d.moduleSpecifier,
    })),
  );
}
Example #4
Source File: helpers.ts    From prisma-nestjs-graphql with MIT License 5 votes vote down vote up
export function testSourceFile(args: {
  project: Project;
  file?: string;
  class?: string;
  property?: string;
}) {
  const { project, file, property, class: className } = args;
  let sourceFile: SourceFile;
  if (file) {
    sourceFile = project.getSourceFileOrThrow(s => s.getFilePath().endsWith(file));
  } else if (className) {
    sourceFile = project.getSourceFileOrThrow(s => Boolean(s.getClass(className)));
  } else {
    throw new TypeError('file or class must be provided');
  }

  const importDeclarations = sourceFile
    .getImportDeclarations()
    .map(d => d.getStructure());
  const classFile = sourceFile.getClass(() => true)!;
  const propertyStructure =
    property && classFile.getProperty(p => p.getName() === property)?.getStructure();
  const propertyDecorators = (
    propertyStructure as PropertyDeclarationStructure | undefined
  )?.decorators;
  const fieldDecorator = propertyDecorators?.find(d => d.name === 'Field');

  type ImportElement = { name: string; specifier: string };
  const namedImports: ImportElement[] = [];
  const namespaceImports: ImportElement[] = [];

  for (const d of importDeclarations) {
    if (d.namespaceImport) {
      namespaceImports.push({
        name: d.namespaceImport,
        specifier: d.moduleSpecifier,
      });
    }
    for (const s of (d.namedImports || []) as ImportSpecifierStructure[]) {
      namedImports.push({
        name: s.name,
        specifier: d.moduleSpecifier,
      });
    }
  }

  return {
    sourceFile,
    classFile,
    sourceText: sourceFile.getText(),
    namedImports,
    namespaceImports,
    property: propertyStructure as PropertyDeclarationStructure | undefined,
    propertyDecorators,
    fieldDecorator,
    fieldDecoratorType: fieldDecorator?.arguments?.[0],
    fieldDecoratorOptions: fieldDecorator?.arguments?.[1],
  };
}
Example #5
Source File: generate-files.ts    From prisma-nestjs-graphql with MIT License 4 votes vote down vote up
export async function generateFiles(args: EventArguments) {
  const { project, config, output, eventEmitter } = args;

  if (config.emitSingle) {
    const rootDirectory =
      project.getDirectory(output) || project.createDirectory(output);
    const sourceFile =
      rootDirectory.getSourceFile('index.ts') ||
      rootDirectory.createSourceFile('index.ts', undefined, { overwrite: true });
    const statements = project.getSourceFiles().flatMap(s => {
      if (s === sourceFile) {
        return [];
      }
      const classDeclaration = s.getClass(() => true);
      const statements = s.getStructure().statements;
      // Reget decorator full name
      // TODO: Check possible bug of ts-morph
      if (Array.isArray(statements)) {
        for (const statement of statements) {
          if (
            !(typeof statement === 'object' && statement.kind === StructureKind.Class)
          ) {
            continue;
          }
          for (const property of statement.properties || []) {
            for (const decorator of property.decorators || []) {
              const fullName = classDeclaration
                ?.getProperty(property.name)
                ?.getDecorator(decorator.name)
                ?.getFullName();
              ok(
                fullName,
                `Cannot get full name of decorator of class ${statement.name!}`,
              );
              decorator.name = fullName;
            }
          }
        }
      }

      project.removeSourceFile(s);
      return statements;
    });
    const imports = new ImportDeclarationMap();
    const enums: (StatementStructures | string)[] = [];
    const classes: ClassDeclarationStructure[] = [];
    for (const statement of statements as (StatementStructures | string)[]) {
      if (typeof statement === 'string') {
        if (statement.startsWith('registerEnumType')) {
          enums.push(statement);
        }
        continue;
      }
      switch (statement.kind) {
        case StructureKind.ImportDeclaration:
          if (
            statement.moduleSpecifier.startsWith('./') ||
            statement.moduleSpecifier.startsWith('..')
          ) {
            continue;
          }
          for (const namedImport of statement.namedImports as ImportSpecifierStructure[]) {
            const name = namedImport.alias || namedImport.name;
            imports.add(name, statement.moduleSpecifier);
          }
          if (statement.defaultImport) {
            imports.create({
              from: statement.moduleSpecifier,
              name: statement.defaultImport,
              defaultImport: statement.defaultImport,
            });
          }
          if (statement.namespaceImport) {
            imports.create({
              from: statement.moduleSpecifier,
              name: statement.namespaceImport,
              namespaceImport: statement.namespaceImport,
            });
          }
          break;
        case StructureKind.Enum:
          enums.unshift(statement);
          break;
        case StructureKind.Class:
          classes.push(statement);
          break;
      }
    }
    sourceFile.set({
      kind: StructureKind.SourceFile,
      statements: [...imports.toStatements(), ...enums, ...classes],
    });
  }

  if (config.emitCompiled) {
    project.compilerOptions.set({
      declaration: true,
      declarationDir: output,
      rootDir: output,
      outDir: output,
      emitDecoratorMetadata: false,
      skipLibCheck: true,
    });
    const emitResult = await project.emit();
    const errors = emitResult.getDiagnostics().map(d => String(d.getMessageText()));
    if (errors.length > 0) {
      eventEmitter.emitSync('Warning', errors);
    }
  } else {
    await project.save();
  }
}
Example #6
Source File: test-generate.ts    From prisma-nestjs-graphql with MIT License 4 votes vote down vote up
export async function testGenerate(args: {
  schema: string;
  options?: string[] | string;
  provider?: 'postgresql' | 'mongodb';
  createSouceFile?: {
    text: string;
    name: string;
    type: string;
  };
  onConnect?: (emitter: AwaitEventEmitter) => void;
}) {
  const { schema, options, provider, createSouceFile, onConnect } = args;
  let project: Project | undefined;
  const connectCallback = (emitter: AwaitEventEmitter) => {
    onConnect && onConnect(emitter);
    if (createSouceFile) {
      emitter.on(
        'PostBegin',
        ({ config, project, output, getModelName }: EventArguments) => {
          const filePath = generateFileName({
            type: createSouceFile.type,
            name: createSouceFile.name,
            getModelName,
            template: config.outputFilePattern,
          });
          project.createSourceFile(`${output}/${filePath}`, createSouceFile.text, {
            overwrite: true,
          });
        },
      );
    }
    emitter.on('End', (args: { project: Project }) => {
      ({ project } = args);
    });
  };
  await generate({
    ...(await createGeneratorOptions(schema, options, provider)),
    skipAddOutputSourceFiles: true,
    connectCallback,
  });

  ok(project, 'Project is not defined');
  const sourceFiles = project.getSourceFiles();
  const emptyFieldsFiles: string[] = [];

  for (const sourceFile of sourceFiles) {
    const filePath = sourceFile.getFilePath();
    const text = sourceFile.getText();
    if (!text) {
      let message = `Project should not contain empty files: ${filePath}`;
      const fileLower = sourceFile
        .getBaseNameWithoutExtension()
        .replace(/-/g, '')
        .split('.')[0];
      const sources = sourceFiles.filter(s =>
        s
          .getClass(() => true)
          ?.getProperties()
          .find(p => String(p.getStructure().type).toLowerCase().includes(fileLower)),
      );
      if (sources.length > 0) {
        message += `, reference: ${sources.map(s => s.getBaseName()).join(', ')}`;
      }
      throw new Error(message);
    }
    const imports = sourceFile
      .getImportDeclarations()
      .map(d => d.getStructure())
      .flatMap(s => {
        return [
          ...((s.namedImports || []) as ImportSpecifierStructure[]).map(x => x.name),
          s.namespaceImport,
        ].filter(Boolean);
      });
    if (uniq(imports).length !== imports.length) {
      throw new Error(`Duplicated import in ${filePath}: ${imports.toString()}`);
    }
    // Find classes without @Field() (must define one or more fields)
    const properties = sourceFile.getClass(() => true)?.getProperties();
    if (properties && !properties.some(p => p.getDecorator('Field'))) {
      emptyFieldsFiles.push(sourceFile.getBaseName());
    }
  }
  if (emptyFieldsFiles.length > 0) {
    throw new Error(`No defined fields in ${emptyFieldsFiles.join(', ')}`);
  }

  return { project, sourceFiles };
}