Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
{
"deno.enable": true,
"deno.unstable": true
"deno.unstable": true,
"editor.formatOnSave": true,
"editor.defaultFormatter": "denoland.vscode-deno",
"[javascript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"[typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"[json]": {
"editor.defaultFormatter": "denoland.vscode-deno"
}
}
1 change: 1 addition & 0 deletions src/commands/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export async function fromConfig(configContents: string) {
.split("---")
.map((v) => v.trim())
.map((v) => yaml.parse(v) as Configuration);

const outputs: Output[] = [];
for (const config of configs) {
const o = await process(config);
Expand Down
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export type Config = { [key: string]: unknown };
export interface Configuration {
spec: string;
config?: Config;
generates: Record<string, Target>;
plugins?: string[];
generates?: Record<string, Target>;
}

export interface Target {
Expand Down
28 changes: 21 additions & 7 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import * as path from "https://deno.land/std@0.167.0/path/mod.ts";
import * as streams from "https://deno.land/std@0.167.0/streams/read_all.ts";

import { Config, Configuration, Output } from "./config.ts";
import { existsSync } from "./utils.ts";
import { existsSync, makeRelativeUrl } from "./utils.ts";

async function processConfig(config: Configuration): Promise<Output[]> {
export async function processConfig(config: Configuration): Promise<Output[]> {
const apexSource = await Deno.readTextFile(config.spec);
// TODO: implement resolver callback
const doc = apex.parse(apexSource);

config = await processPlugin(doc, config);

const output: Output[] = [];
for (const file in config.generates) {
const generatorConfig = config.generates[file];
Expand All @@ -21,11 +23,7 @@ async function processConfig(config: Configuration): Promise<Output[]> {
//log.info(`Skipping ${file}`);
continue;
}

const url = generatorConfig.module.startsWith(".") ||
generatorConfig.module.startsWith("/")
? new URL("file:///" + path.join(Deno.cwd(), generatorConfig.module))
: new URL(generatorConfig.module);
const url = makeRelativeUrl(generatorConfig.module);

const visitorConfig: Config = {};
if (config.config) {
Expand Down Expand Up @@ -68,6 +66,22 @@ async function processConfig(config: Configuration): Promise<Output[]> {
return output;
}

export async function processPlugin(
doc: apex.ast.Document,
config: Configuration,
): Promise<Configuration> {
for (const file of config.plugins || []) {
const url = makeRelativeUrl(file);

log.debug(`Generating configuration with plugin from ${url}`);

const plugin = await import(url.toString());
config = plugin.default(doc, config);
}

return config;
}

// Detect piped input
if (!Deno.isatty(Deno.stdin.rid) && import.meta.main) {
const stdinContent = await streams.readAll(Deno.stdin);
Expand Down
8 changes: 7 additions & 1 deletion src/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Configuration, Output } from "./config.ts";
import { cliFormatters, sourceFormatters } from "./formatters.ts";

export async function process(config: Configuration): Promise<Output[]> {
log.debug(`Configuration is: ${JSON.stringify(config, null, 2)}`);

// Run the generation process with restricted permissions.
const href = new URL("./generate.ts", import.meta.url).href;
const p = await Deno.run({
Expand Down Expand Up @@ -38,6 +40,7 @@ export async function process(config: Configuration): Promise<Output[]> {
}

const output = new TextDecoder().decode(rawOutput);
log.debug(`Generator output: ${output}`);
return JSON.parse(output) as Output[];
}

Expand Down Expand Up @@ -68,7 +71,10 @@ export async function writeOutput(generated: Output): Promise<void> {
// Execute additional tooling via "runAfter".
if (generated.runAfter) {
generated.runAfter.forEach(async (cmdConfig) => {
const joined = cmdConfig.command.trim().split("\n").map((v) => v.trim())
const joined = cmdConfig.command
.trim()
.split("\n")
.map((v) => v.trim())
.join(" ");
const args = joined.split(/\s+/);
const cmd = args.shift()!;
Expand Down
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,11 @@ export async function mkdirAll(path: string, mode: number) {
}
}
}

export function makeRelativeUrl(file: string): URL {
return file.startsWith(".")
? new URL("file:///" + path.join(Deno.cwd(), file))
: file.startsWith("/")
? new URL("file:///" + file)
: new URL(file);
}
15 changes: 8 additions & 7 deletions test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as path from "https://deno.land/std@0.167.0/path/mod.ts";

const __dirname = new URL(".", import.meta.url).pathname;

// Compact form: name and function
Deno.test(
"process",
{ permissions: { read: true, net: true, run: true } },
Expand All @@ -20,10 +19,12 @@ Deno.test(
});

const fixture = await Deno.readTextFile(path.join(__dirname, "fixture.rs"));
assertEquals(generated, [{
file: "file.rs",
source: fixture,
executable: false,
}]);
},
assertEquals(generated, [
{
file: "file.rs",
source: fixture,
executable: false,
},
]);
}
);
69 changes: 69 additions & 0 deletions test/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as apex from "https://deno.land/x/apex_core@v0.1.1/mod.ts";
import { assertEquals } from "https://deno.land/std@0.167.0/testing/asserts.ts";
import { processPlugin, processConfig } from "../src/generate.ts";
import * as path from "https://deno.land/std@0.167.0/path/mod.ts";

const __dirname = new URL(".", import.meta.url).pathname;
const spec = path.join(__dirname, "test.axdl");
const plugin = path.join(__dirname, "test-plugin.ts");
const generator = path.join(__dirname, "test-generator.ts");

Deno.test(
"plugin",
{ permissions: { read: true, net: true, run: true } },
async () => {
const apexSource = await Deno.readTextFile(spec);
const doc = apex.parse(apexSource);
const config = await processPlugin(doc, {
spec,
plugins: [plugin],
});

assertEquals(config.generates, { "Test.0.file": { module: generator } });
}
);

Deno.test(
"plugin",
{ permissions: { read: true, net: true, run: true } },
async () => {
const apexSource = await Deno.readTextFile(spec);
const doc = apex.parse(apexSource);
const config = await processPlugin(doc, {
spec,
plugins: [plugin, plugin],
});

assertEquals(config.generates, {
"Test.0.file": { module: generator },
"Test.1.file": { module: generator },
});
}
);

Deno.test(
"generate",
{ permissions: { read: true, net: true, run: true } },
async () => {
const apexSource = await Deno.readTextFile(spec);
const output = await processConfig({
spec,
plugins: [plugin, plugin],
});

assertEquals(output, [
{
file: "Test.0.file",
source: "startend",
executable: false,
runAfter: undefined,
},
{
file: "Test.1.file",
source: "startend",
executable: false,
runAfter: undefined,
},
]);
}
);
15 changes: 15 additions & 0 deletions test/test-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as model from "https://deno.land/x/apex_core@v0.1.0/model/mod.ts";

type Context = model.Context;

export default class DefaultVisitor extends model.BaseVisitor {
visitContextBefore(context: Context): void {
super.visitContextBefore(context);
this.write("start");
}

visitContextAfter(context: Context): void {
super.visitContextAfter(context);
this.write("end");
}
}
23 changes: 23 additions & 0 deletions test/test-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Configuration } from "../src/config.ts";
import * as apex from "https://deno.land/x/apex_core@v0.1.0/mod.ts";
import * as path from "https://deno.land/std@0.167.0/path/mod.ts";

const __dirname = new URL(".", import.meta.url).pathname;
const generator = path.join(__dirname, "test-generator.ts");

export default function (
doc: apex.ast.Document,
config: Configuration
): Configuration {
config.generates ||= {};
const interfaces = doc.definitions.filter(
(def) => def.getKind() === apex.ast.Kind.InterfaceDefinition
) as apex.ast.InterfaceDefinition[];
const num = Object.keys(config.generates).length;
for (const iface of interfaces) {
config.generates[`${iface.name.value}.${num}.file`] = {
module: generator,
};
}
return config;
}