Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

rollup-plugin-dts

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rollup-plugin-dts - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

5

CHANGELOG.md

@@ -0,1 +1,6 @@

### 1.0.0 2019-06-07
- Re-add support for directly using `.ts` files.
- Fix type parameters with `extends` constraints.
### 1.0.0 2019-06-05

@@ -2,0 +7,0 @@

394

dist/rollup-plugin-dts.js

@@ -6,2 +6,3 @@ 'use strict';

var ts = require('typescript');
var path = require('path');

@@ -63,2 +64,184 @@ function getCodeFrame() {

class NamespaceFixer {
constructor(sourceFile) {
this.sourceFile = sourceFile;
}
findNamespaces() {
const namespaces = [];
const itemTypes = {};
for (const node of this.sourceFile.statements) {
if (ts.isClassDeclaration(node)) {
itemTypes[node.name.getText()] = "class";
}
else if (ts.isFunctionDeclaration(node)) {
itemTypes[node.name.getText()] = "function";
}
else if (ts.isInterfaceDeclaration(node)) {
itemTypes[node.name.getText()] = "interface";
}
else if (ts.isModuleDeclaration(node)) {
itemTypes[node.name.getText()] = "namespace";
}
else if (ts.isEnumDeclaration(node)) {
itemTypes[node.name.getText()] = "enum";
}
if (!ts.isVariableStatement(node)) {
continue;
}
const { declarations } = node.declarationList;
if (declarations.length !== 1) {
continue;
}
const decl = declarations[0];
const name = decl.name.getText();
if (!decl.initializer || !ts.isCallExpression(decl.initializer)) {
itemTypes[name] = "var";
continue;
}
const obj = decl.initializer.arguments[0];
if (!decl.initializer.expression.getFullText().includes("/*#__PURE__*/Object.freeze") ||
!ts.isObjectLiteralExpression(obj)) {
continue;
}
const exports = [];
for (const prop of obj.properties) {
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name) || !ts.isIdentifier(prop.initializer)) {
throw new UnsupportedSyntaxError(prop, "Expected a property assignment");
}
exports.push({
exportedName: prop.name.getText(),
localName: prop.initializer.getText(),
});
}
// sort in reverse order, since we will do string manipulation
namespaces.unshift({
name,
exports,
location: {
start: node.getStart(),
end: node.getEnd(),
},
});
}
return { namespaces, itemTypes };
}
fix() {
let code = this.sourceFile.getText();
const { namespaces, itemTypes } = this.findNamespaces();
for (const ns of namespaces) {
const codeAfter = code.slice(ns.location.end);
code = code.slice(0, ns.location.start);
for (const { exportedName, localName } of ns.exports) {
if (exportedName === localName) {
const type = itemTypes[localName];
if (type === "interface") {
// an interface is just a type
code += `type ${ns.name}_${exportedName} = ${localName};\n`;
}
else if (type === "enum" || type === "class") {
// enums and classes are both types and values
code += `type ${ns.name}_${exportedName} = ${localName};\n`;
code += `declare const ${ns.name}_${exportedName}: typeof ${localName};\n`;
}
else {
// functions and vars are just values
code += `declare const ${ns.name}_${exportedName}: typeof ${localName};\n`;
}
}
}
code += `declare namespace ${ns.name} {\n`;
code += ` export {\n`;
for (const { exportedName, localName } of ns.exports) {
if (exportedName === localName) {
code += ` ${ns.name}_${exportedName} as ${exportedName},\n`;
}
else {
code += ` ${localName} as ${exportedName}\n`;
}
}
code += ` };\n`;
code += `}`;
code += codeAfter;
}
return code;
}
}
const dts = ".d.ts";
const formatHost = {
getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
getNewLine: () => ts.sys.newLine,
getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? f => f : f => f.toLowerCase(),
};
const OPTIONS_OVERRIDE = {
// Ensure ".d.ts" modules are generated
declaration: true,
// Skip ".js" generation
emitDeclarationOnly: true,
// Skip code generation when error occurs
noEmitOnError: true,
// Avoid extra work
checkJs: false,
declarationMap: false,
skipLibCheck: true,
// Ensure TS2742 errors are visible
preserveSymlinks: true,
};
function getCompilerOptions(input) {
let dirName = path.dirname(input);
const configPath = ts.findConfigFile(path.dirname(input), ts.sys.fileExists);
if (!configPath) {
return { dirName, compilerOptions: Object.assign({}, OPTIONS_OVERRIDE) };
}
dirName = path.dirname(configPath);
const { config, error } = ts.readConfigFile(configPath, ts.sys.readFile);
if (error) {
console.error(ts.formatDiagnostic(error, formatHost));
return { dirName, compilerOptions: Object.assign({}, OPTIONS_OVERRIDE) };
}
const { options, errors } = ts.parseJsonConfigFileContent(config, ts.sys, dirName);
if (errors.length) {
console.error(ts.formatDiagnostics(errors, formatHost));
return { dirName, compilerOptions: Object.assign({}, OPTIONS_OVERRIDE) };
}
return {
dirName,
compilerOptions: Object.assign({}, options, OPTIONS_OVERRIDE),
};
}
function createPrograms(input) {
const programs = [];
let inputs = [];
let dirName = "";
let compilerOptions = {};
for (let main of input) {
if (main.endsWith(dts)) {
continue;
}
main = path.resolve(main);
const options = getCompilerOptions(main);
if (!inputs.length) {
inputs.push(main);
({ dirName, compilerOptions } = options);
continue;
}
if (options.dirName === dirName) {
inputs.push(main);
}
else {
const host = ts.createCompilerHost(compilerOptions, true);
const program = ts.createProgram(inputs, compilerOptions, host);
programs.push(program);
inputs = [main];
({ dirName, compilerOptions } = options);
}
}
if (inputs.length) {
const host = ts.createCompilerHost(compilerOptions, true);
const program = ts.createProgram(inputs, compilerOptions, host);
programs.push(program);
}
return programs;
}
const MARKER = "0";

@@ -321,5 +504,6 @@ let IDs = 1;

for (const node of params) {
this.convertTypeNode(node.constraint);
this.convertTypeNode(node.default);
this.pushScope();
this.pushTypeVariable(node.name);
this.convertTypeNode(node.default);
}

@@ -788,111 +972,52 @@ return params.length;

class NamespaceFixer {
constructor(sourceFile) {
this.sourceFile = sourceFile;
const tsx = /\.tsx?$/;
// Parse a TypeScript module into an ESTree program.
function transformFile(input) {
const transformer = new Transformer(input);
const { ast, fixups } = transformer.transform();
// NOTE(swatinem):
// hm, typescript generates `export default` without a declare,
// but rollup moves the `export default` to a different place, which leaves
// the function declaration without a `declare`.
// Well luckily both words have the same length, haha :-D
let code = input.getText();
code = code.replace(/(export\s+)default(\s+(function|class))/m, "$1declare$2");
for (const fixup of fixups) {
code = code.slice(0, fixup.range.start) + fixup.identifier + code.slice(fixup.range.end);
}
findNamespaces() {
const namespaces = [];
const itemTypes = {};
for (const node of this.sourceFile.statements) {
if (ts.isClassDeclaration(node)) {
itemTypes[node.name.getText()] = "class";
return { code, ast };
}
const plugin = () => {
// There exists one Program object per entry point,
// except when all entry points are ".d.ts" modules.
let programs = [];
function getModule(fileName) {
let source;
let program;
if (programs.length) {
// Rollup doesn't tell you the entry point of each module in the bundle,
// so we need to ask every TypeScript program for the given filename.
for (program of programs) {
source = program.getSourceFile(fileName);
if (source)
break;
}
else if (ts.isFunctionDeclaration(node)) {
itemTypes[node.name.getText()] = "function";
}
else if (ts.isInterfaceDeclaration(node)) {
itemTypes[node.name.getText()] = "interface";
}
else if (ts.isModuleDeclaration(node)) {
itemTypes[node.name.getText()] = "namespace";
}
else if (ts.isEnumDeclaration(node)) {
itemTypes[node.name.getText()] = "enum";
}
if (!ts.isVariableStatement(node)) {
continue;
}
const { declarations } = node.declarationList;
if (declarations.length !== 1) {
continue;
}
const decl = declarations[0];
const name = decl.name.getText();
if (!decl.initializer || !ts.isCallExpression(decl.initializer)) {
itemTypes[name] = "var";
continue;
}
const obj = decl.initializer.arguments[0];
if (!decl.initializer.expression.getFullText().includes("/*#__PURE__*/Object.freeze") ||
!ts.isObjectLiteralExpression(obj)) {
continue;
}
const exports = [];
for (const prop of obj.properties) {
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name) || !ts.isIdentifier(prop.initializer)) {
throw new UnsupportedSyntaxError(prop, "Expected a property assignment");
}
exports.push({
exportedName: prop.name.getText(),
localName: prop.initializer.getText(),
});
}
// sort in reverse order, since we will do string manipulation
namespaces.unshift({
name,
exports,
location: {
start: node.getStart(),
end: node.getEnd(),
},
});
}
return { namespaces, itemTypes };
}
fix() {
let code = this.sourceFile.getText();
const { namespaces, itemTypes } = this.findNamespaces();
for (const ns of namespaces) {
const codeAfter = code.slice(ns.location.end);
code = code.slice(0, ns.location.start);
for (const { exportedName, localName } of ns.exports) {
if (exportedName === localName) {
const type = itemTypes[localName];
if (type === "interface") {
// an interface is just a type
code += `type ${ns.name}_${exportedName} = ${localName};\n`;
}
else if (type === "enum" || type === "class") {
// enums and classes are both types and values
code += `type ${ns.name}_${exportedName} = ${localName};\n`;
code += `declare const ${ns.name}_${exportedName}: typeof ${localName};\n`;
}
else {
// functions and vars are just values
code += `declare const ${ns.name}_${exportedName}: typeof ${localName};\n`;
}
}
}
code += `declare namespace ${ns.name} {\n`;
code += ` export {\n`;
for (const { exportedName, localName } of ns.exports) {
if (exportedName === localName) {
code += ` ${ns.name}_${exportedName} as ${exportedName},\n`;
}
else {
code += ` ${localName} as ${exportedName}\n`;
}
}
code += ` };\n`;
code += `}`;
code += codeAfter;
// Create any `ts.SourceFile` objects on-demand for ".d.ts" modules,
// but only when there are zero ".ts" entry points.
else if (fileName.endsWith(dts)) {
const code = ts.sys.readFile(fileName, "utf8");
if (code)
source = ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, true);
}
return code;
return { source, program };
}
}
const plugin = () => {
return {
name: "dts",
options(options) {
let { input } = options;
if (!Array.isArray(input)) {
input = !input ? [] : typeof input === "string" ? [input] : Object.values(input);
}
programs = createPrograms(input);
return Object.assign({}, options, { treeshake: {

@@ -904,4 +1029,35 @@ moduleSideEffects: "no-external",

outputOptions(options) {
return Object.assign({}, options, { chunkFileNames: options.chunkFileNames || "[name]-[hash].d.ts", entryFileNames: options.entryFileNames || "[name].d.ts", format: "es", exports: "named", compact: false, freeze: true, interop: false, namespaceToStringTag: false, strict: false });
return Object.assign({}, options, { chunkFileNames: options.chunkFileNames || "[name]-[hash]" + dts, entryFileNames: options.entryFileNames || "[name]" + dts, format: "es", exports: "named", compact: false, freeze: true, interop: false, namespaceToStringTag: false, strict: false });
},
load(id) {
if (!tsx.test(id)) {
return null;
}
if (id.endsWith(dts)) {
const { source } = getModule(id);
return source ? transformFile(source) : null;
}
// Always try ".d.ts" before ".tsx?"
const declarationId = id.replace(tsx, dts);
let module = getModule(declarationId);
if (module.source) {
return transformFile(module.source);
}
// Generate in-memory ".d.ts" modules from ".tsx?" modules!
module = getModule(id);
if (!module.source || !module.program) {
return null;
}
let generated;
const { emitSkipped, diagnostics } = module.program.emit(module.source, (_, declarationText) => (generated = transformFile(ts.createSourceFile(declarationId, declarationText, ts.ScriptTarget.Latest, true))), undefined, // cancellationToken
true);
if (emitSkipped) {
const errors = diagnostics.filter(diag => diag.category === ts.DiagnosticCategory.Error);
if (errors.length) {
console.error(ts.formatDiagnostics(errors, formatHost));
this.error("Failed to compile. Check the logs above.");
}
}
return generated;
},
resolveId(source, importer) {

@@ -918,32 +1074,6 @@ if (!importer) {

// maybe its a good idea to introduce an option for this?
if (resolvedModule.isExternalLibraryImport) {
return { id: source, external: true };
}
let id = resolvedModule.resolvedFileName;
const { extension } = resolvedModule;
if (extension !== ".d.ts") {
// ts resolves `.ts`/`.tsx` files before `.d.ts`
id = id.slice(0, id.length - extension.length) + ".d.ts";
}
return { id };
return resolvedModule.isExternalLibraryImport
? { id: source, external: true }
: { id: resolvedModule.resolvedFileName };
},
transform(code, id) {
if (!id.endsWith(".d.ts")) {
this.error("`rollup-plugin-dts` can only deal with `.d.ts` files.");
return;
}
const dtsSource = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
const converter = new Transformer(dtsSource);
const { ast, fixups } = converter.transform();
// NOTE(swatinem):
// hm, typescript generates `export default` without a declare,
// but rollup moves the `export default` to a different place, which leaves
// the function declaration without a `declare`.
// Well luckily both words have the same length, haha :-D
code = code.replace(/(export\s+)default(\s+(function|class))/m, "$1declare$2");
for (const fixup of fixups) {
code = code.slice(0, fixup.range.start) + fixup.identifier + code.slice(fixup.range.end);
}
return { code, ast };
},
renderChunk(code, chunk) {

@@ -950,0 +1080,0 @@ const source = ts.createSourceFile(chunk.fileName, code, ts.ScriptTarget.Latest, true);

{
"name": "rollup-plugin-dts",
"version": "1.0.0",
"version": "1.1.0",
"description": "An experiment to generate .d.ts rollup files",

@@ -70,3 +70,3 @@ "keywords": [

"react": "^16.8.6",
"rollup": "^1.13.1",
"rollup": "^1.14.3",
"ts-jest": "^24.0.2",

@@ -73,0 +73,0 @@ "typescript": "3.5.1"

@@ -40,10 +40,2 @@ # rollup-plugin-dts

## Prerequisites
The plugin works by consuming pre-generated `.d.ts` files. So you will need to
set up your `tsc` compiler or any other tool to output `.d.ts` files.
You can do so by specifying either `declaration: true`
or `emitDeclarationOnly: true` in your `tsconfig.json` file. Then point
rollup to the output.
## Why?

@@ -50,0 +42,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc