Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix addSource to allow implementation path to point to a file #212

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 39 additions & 15 deletions lib/transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,62 @@ class Transformer {
}
});

this.sources = []; // Absolute paths to the IDL and Impl directories.
this._sources = []; // Absolute paths to the IDL and Impl files or directories.
this.utilPath = null;
}

addSource(idl, impl) {
if (typeof idl !== "string") {
throw new TypeError("idl path has to be a string");
}

if (typeof impl !== "string") {
throw new TypeError("impl path has to be a string");
}
this.sources.push({ idlPath: path.resolve(idl), impl: path.resolve(impl) });

this._sources.push({
idlPath: path.resolve(idl),
implPath: path.resolve(impl)
});

return this;
}

async _collectSources() {
const stats = await Promise.all(this.sources.map(src => fs.stat(src.idlPath)));
const { implSuffix } = this.ctx;
const stats = await Promise.all(this._sources.map(src => Promise.all([
fs.stat(src.idlPath),
fs.stat(src.implPath)
])));

const files = [];
for (let i = 0; i < stats.length; ++i) {
if (stats[i].isDirectory()) {
const folderContents = await fs.readdir(this.sources[i].idlPath);
const { idlPath, implPath } = this._sources[i];
const [idlStat, implStat] = stats[i];

if (idlStat.isDirectory()) {
if (!implStat.isDirectory()) {
throw new Error("Internal error: When the idl path is a directory, the impl path must also be a directory.");
}

const folderContents = await fs.readdir(this._sources[i].idlPath);
for (const file of folderContents) {
if (file.endsWith(".webidl")) {
if (path.extname(file) === ".webidl") {
files.push({
idlPath: path.join(this.sources[i].idlPath, file),
impl: this.sources[i].impl
idlPath: path.join(idlPath, file),
implPath: path.join(implPath, `${path.basename(file, ".webidl")}${implSuffix}.js`)
});
}
}
} else if (implStat.isDirectory()) {
files.push({
idlPath,
implPath: path.join(implPath, `${path.basename(idlPath, ".webidl")}${implSuffix}.js`)
});
} else {
files.push({
idlPath: this.sources[i].idlPath,
impl: this.sources[i].impl
idlPath,
implPath
});
}
}
Expand All @@ -71,7 +94,7 @@ class Transformer {
for (let i = 0; i < files.length; ++i) {
zipped.push({
idlContent: fileContents[i],
impl: files[i].impl
implPath: files[i].implPath
});
}
return zipped;
Expand All @@ -80,7 +103,7 @@ class Transformer {
_parse(outputDir, contents) {
const parsed = contents.map(content => ({
idl: webidl.parse(content.idlContent),
impl: content.impl
impl: content.implPath
}));

this.ctx.initialize();
Expand All @@ -97,7 +120,7 @@ class Transformer {
}

obj = new Interface(this.ctx, instruction, {
implDir: file.impl
implFile: file.impl
});
interfaces.set(obj.name, obj);
break;
Expand Down Expand Up @@ -208,7 +231,7 @@ class Transformer {
for (const obj of interfaces.values()) {
let source = obj.toString();

let implFile = path.relative(outputDir, path.resolve(obj.opts.implDir, obj.name + this.ctx.implSuffix));
let implFile = path.relative(outputDir, obj.opts.implFile);
implFile = implFile.replace(/\\/g, "/"); // fix windows file paths
if (implFile[0] !== ".") {
implFile = "./" + implFile;
Expand All @@ -220,7 +243,7 @@ class Transformer {
const conversions = require("webidl-conversions");
const utils = require("${relativeUtils}");
${source}
const Impl = require("${implFile}.js");
const Impl = require("${implFile}");
`;

source = this._prettify(source);
Expand Down Expand Up @@ -250,6 +273,7 @@ class Transformer {

${obj.toString()}
`);

await fs.writeFile(path.join(outputDir, obj.name + ".js"), source);
}
}
Expand Down
109 changes: 109 additions & 0 deletions test/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,114 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Transformer API addSource implementation file custom path 1`] = `
"\\"use strict\\";

const conversions = require(\\"webidl-conversions\\");
const utils = require(\\"./utils.js\\");

const implSymbol = utils.implSymbol;
const ctorRegistrySymbol = utils.ctorRegistrySymbol;

const interfaceName = \\"Foo\\";

exports.is = value => {
return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
};
exports.isImpl = value => {
return utils.isObject(value) && value instanceof Impl.implementation;
};
exports.convert = (value, { context = \\"The provided value\\" } = {}) => {
if (exports.is(value)) {
return utils.implForWrapper(value);
}
throw new TypeError(\`\${context} is not of type 'Foo'.\`);
};

function makeWrapper(globalObject) {
if (globalObject[ctorRegistrySymbol] === undefined) {
throw new Error(\\"Internal error: invalid global object\\");
}

const ctor = globalObject[ctorRegistrySymbol][\\"Foo\\"];
if (ctor === undefined) {
throw new Error(\\"Internal error: constructor Foo is not installed on the passed global object\\");
}

return Object.create(ctor.prototype);
}

exports.create = (globalObject, constructorArgs, privateData) => {
const wrapper = makeWrapper(globalObject);
return exports.setup(wrapper, globalObject, constructorArgs, privateData);
};

exports.createImpl = (globalObject, constructorArgs, privateData) => {
const wrapper = exports.create(globalObject, constructorArgs, privateData);
return utils.implForWrapper(wrapper);
};

exports._internalSetup = (wrapper, globalObject) => {};

exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
privateData.wrapper = wrapper;

exports._internalSetup(wrapper, globalObject);
Object.defineProperty(wrapper, implSymbol, {
value: new Impl.implementation(globalObject, constructorArgs, privateData),
configurable: true
});

wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
if (Impl.init) {
Impl.init(wrapper[implSymbol]);
}
return wrapper;
};

exports.new = globalObject => {
const wrapper = makeWrapper(globalObject);

exports._internalSetup(wrapper, globalObject);
Object.defineProperty(wrapper, implSymbol, {
value: Object.create(Impl.implementation.prototype),
configurable: true
});

wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
if (Impl.init) {
Impl.init(wrapper[implSymbol]);
}
return wrapper[implSymbol];
};

const exposed = new Set([\\"Window\\"]);

exports.install = (globalObject, globalNames) => {
if (!globalNames.some(globalName => exposed.has(globalName))) {
return;
}
class Foo {
constructor() {
throw new TypeError(\\"Illegal constructor\\");
}
}
Object.defineProperties(Foo.prototype, { [Symbol.toStringTag]: { value: \\"Foo\\", configurable: true } });
if (globalObject[ctorRegistrySymbol] === undefined) {
globalObject[ctorRegistrySymbol] = Object.create(null);
}
globalObject[ctorRegistrySymbol][interfaceName] = Foo;

Object.defineProperty(globalObject, interfaceName, {
configurable: true,
writable: true,
value: Foo
});
};

const Impl = require(\\"../fixtures/custom-path/impl-file.js\\");
"
`;

exports[`with processors AsyncCallbackInterface.webidl 1`] = `
"\\"use strict\\";

Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/custom-path/impl-file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";

exports.implementation = class FooImpl {
constructor(globalObject, args, privateData) {
this._globalObject = globalObject;
this._args = args;
this._privateData = privateData;
}
};
3 changes: 3 additions & 0 deletions test/fixtures/custom-path/some.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[Exposed=Window]
interface Foo {
};
22 changes: 22 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,31 @@ const rootDir = path.resolve(__dirname, "..");
const casesDir = path.resolve(__dirname, "cases");
const implsDir = path.resolve(__dirname, "implementations");
const outputDir = path.resolve(__dirname, "output");
const fixturesDir = path.resolve(__dirname, "fixtures");

const idlFiles = fs.readdirSync(casesDir);

describe("Transformer API", () => {
describe("addSource", () => {
test("implementation file custom path", async () => {
const customPathDir = path.resolve(fixturesDir, "custom-path");

const transformer = new Transformer({ implSuffix: "-impl" });
transformer.addSource(
path.join(customPathDir, "some.webidl"),
path.join(customPathDir, "impl-file.js")
);

await transformer.generate(outputDir);

const outputFile = path.resolve(outputDir, "Foo.js");
const output = fs.readFileSync(outputFile, { encoding: "utf-8" });

expect(output).toMatchSnapshot();
});
});
});

describe("without processors", () => {
beforeAll(() => {
const transformer = new Transformer();
Expand Down