Skip to content

Commit

Permalink
Workaround for @parcel/transformer-typescript-types in monorepo (parc…
Browse files Browse the repository at this point in the history
  • Loading branch information
mischnic authored Jul 29, 2020
1 parent 1bb0498 commit e449b1a
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 11 deletions.
16 changes: 14 additions & 2 deletions packages/core/fs/src/MemoryFS.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,17 @@ export class MemoryFS implements FileSystem {
}
}

for (let [from] of this.symlinks) {
if (from.startsWith(dir) && from.indexOf(path.sep, dir.length) === -1) {
let name = from.slice(dir.length);
if (opts?.withFileTypes) {
res.push(new Dirent(name, {mode: S_IFLNK}));
} else {
res.push(name);
}
}
}

return res;
}

Expand Down Expand Up @@ -709,6 +720,7 @@ class WriteStream extends Writable {

const S_IFREG = 0o100000;
const S_IFDIR = 0o040000;
const S_IFLNK = 0o120000;

class Entry {
mode: number;
Expand Down Expand Up @@ -813,7 +825,7 @@ class Dirent {
name: string;
#mode: number;

constructor(name: string, entry: Entry) {
constructor(name: string, entry: {mode: number, ...}) {
this.name = name;
this.#mode = entry.mode;
}
Expand All @@ -835,7 +847,7 @@ class Dirent {
}

isSymbolicLink(): boolean {
return false;
return Boolean(this.#mode & S_IFLNK);
}

isFIFO(): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "a",
"version": "0.0.0",
"source": "src/index.ts",
"types": "dist/index.d.ts"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { B } from "b";

export default function () {
return new B();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "b",
"version": "0.0.0",
"source": "src/index.ts",
"types": "dist/index.d.ts",
"main": "dist/index.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export class B {}
export * from "./other";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class C {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"private": true,
"workspaces": [
"a",
"b"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


35 changes: 34 additions & 1 deletion packages/core/integration-tests/test/ts-types.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import assert from 'assert';
import path from 'path';
import {bundle, assertBundles, outputFS, inputFS} from '@parcel/test-utils';
import {
assertBundles,
bundle,
inputFS,
overlayFS,
outputFS,
ncp,
} from '@parcel/test-utils';

describe('typescript types', function() {
it('should generate a typescript declaration file', async function() {
Expand Down Expand Up @@ -188,4 +195,30 @@ describe('typescript types', function() {
);
assert.equal(dist, expected);
});

it('should correctly reference unbuilt monorepo packages', async function() {
let fixtureDir = path.join(__dirname, 'integration/ts-types/monorepo');
await outputFS.mkdirp(path.join(fixtureDir, 'node_modules'));
await ncp(fixtureDir, fixtureDir);
await outputFS.symlink(
path.join(fixtureDir, 'b'),
path.join(fixtureDir, 'node_modules/b'),
);

let b = await bundle(path.join(fixtureDir, 'a'), {
inputFS: overlayFS,
});
assertBundles(b, [
{
type: 'ts',
assets: ['index.ts'],
},
]);

let dist = (
await outputFS.readFile(b.getBundles()[0].filePath, 'utf8')
).replace(/\r\n/g, '\n');

assert(/import\s*{\s*B\s*}\s*from\s*"b";/.test(dist));
});
});
2 changes: 2 additions & 0 deletions packages/core/integration-tests/test/watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ describe('watcher', function() {
if (e.code == 'EPERM') {
symlinkPrivilegeWarning();
this.skip();
} else {
throw e;
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ export default (new Transformer({
moduleResolution: ts.ModuleResolutionKind.NodeJs,
};

let host = new CompilerHost(options.inputFS, ts);
let host = new CompilerHost(options.inputFS, ts, logger);
// $FlowFixMe
let program = ts.createProgram([asset.filePath], opts, host);

let includedFiles = program
.getSourceFiles()
.filter(file => path.normalize(file.fileName) !== asset.filePath)
.map(file => ({filePath: file.fileName}));
.map(file => ({
filePath: host.redirectTypes.get(file.fileName) ?? file.fileName,
}));

let mainModuleName = path
.relative(program.getCommonSourceDirectory(), asset.filePath)
Expand Down
65 changes: 59 additions & 6 deletions packages/utils/ts-utils/src/CompilerHost.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,75 @@
// @flow
import type {FilePath} from '@parcel/types';
import type {FileSystem} from '@parcel/fs';
import type {FilePath, PackageJSON} from '@parcel/types';
import type {PluginLogger} from '@parcel/logger';
import typeof TypeScriptModule from 'typescript'; // eslint-disable-line import/no-extraneous-dependencies
import type {CompilerOptions, SourceFile} from 'typescript';
import typeof {ScriptTarget} from 'typescript'; // eslint-disable-line import/no-extraneous-dependencies

import path from 'path';
import {FSHost} from './FSHost';

export class CompilerHost extends FSHost {
outputCode: ?string;
outputMap: ?string;
logger: PluginLogger;
// workaround for https://github.com/microsoft/TypeScript/issues/39547
redirectTypes: Map<FilePath, FilePath> = new Map();

constructor(fs: FileSystem, ts: TypeScriptModule, logger: PluginLogger) {
super(fs, ts);
this.logger = logger;
}

readFile(filePath: FilePath): void | string {
let contents = super.readFile(filePath);
if (contents && path.basename(filePath) === 'package.json') {
let json: PackageJSON = JSON.parse(contents);
if (
json.types != null &&
json.source != null &&
!super.fileExists(
path.posix.join(path.posix.dirname(filePath), json.types),
)
) {
let source = path.posix.join(path.posix.dirname(filePath), json.source);
let fakeTypes =
source.slice(0, -path.posix.extname(source).length) + '.d.ts';
this.redirectTypes.set(fakeTypes, source);
json.types = fakeTypes;
this.logger.verbose({
message: `Faking missing \`types\` field in ${filePath} to be ${source}`,
});
return JSON.stringify(json);
}
}
return contents;
}

fileExists(filePath: FilePath): boolean {
if (this.redirectTypes.has(filePath)) {
return true;
} else {
return super.fileExists(filePath);
}
}

getSourceFile(
filePath: FilePath,
languageVersion: $Values<ScriptTarget>,
): void | SourceFile {
const sourceText = this.readFile(filePath);
return sourceText !== undefined
? this.ts.createSourceFile(filePath, sourceText, languageVersion)
: undefined;
let redirect = this.redirectTypes.get(filePath);
if (redirect != null) {
const sourceText = this.readFile(redirect);
return sourceText !== undefined
? this.ts.createSourceFile(filePath, sourceText, languageVersion)
: undefined;
} else {
const sourceText = this.readFile(filePath);
return sourceText !== undefined
? this.ts.createSourceFile(filePath, sourceText, languageVersion)
: undefined;
}
}

getDefaultLibFileName(options: CompilerOptions): string {
Expand All @@ -31,7 +84,7 @@ export class CompilerHost extends FSHost {
}
}

getCanonicalFileName(fileName: FilePath): FilePath | string {
getCanonicalFileName(fileName: FilePath): FilePath {
return this.ts.sys.useCaseSensitiveFileNames
? fileName
: fileName.toLowerCase();
Expand Down

0 comments on commit e449b1a

Please sign in to comment.