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
4 changes: 2 additions & 2 deletions packages/build/src/containers/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export class Container {
return this.inversifyContainer.get<T>(type);
}

public load(options: IBuildOptions) {
public async load(options: IBuildOptions) {
const coreContainer = new CoreContainer();
coreContainer.load(options);
await coreContainer.load(options);
this.inversifyContainer.parent = coreContainer.getInversifyContainer();
this.inversifyContainer.load(schemaParserModule(options.schemaParser));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { AllTemplateMetadata, APISchema } from '@vulcan/core';
import { SchemaParserMiddleware } from './middleware';

interface ErrorCode {
code: string;
lineNo: number;
columnNo: number;
}

// Add error code to definition if it is used in query but not defined in schema
export const addMissingErrors =
(allMetadata: AllTemplateMetadata): SchemaParserMiddleware =>
Expand All @@ -10,9 +16,10 @@ export const addMissingErrors =
const templateName = transformedSchemas.templateSource;
const metadata = allMetadata[templateName];
// Skip validation if no metadata found
if (!metadata?.errors) return;
if (!metadata?.['error.vulcan.com']) return;

metadata.errors.forEach((error) => {
const errorCodes: ErrorCode[] = metadata['error.vulcan.com'].errorCodes;
errorCodes.forEach((error) => {
if (!transformedSchemas.errors.some((e) => e.code === error.code)) {
transformedSchemas.errors.push({
code: error.code,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { AllTemplateMetadata, APISchema } from '@vulcan/core';
import { SchemaParserMiddleware } from './middleware';

interface Parameter {
name: string;
lineNo: number;
columnNo: number;
}

export const checkParameter =
(allMetadata: AllTemplateMetadata): SchemaParserMiddleware =>
async (schemas, next) => {
Expand All @@ -9,9 +15,9 @@ export const checkParameter =
const templateName = transformedSchemas.templateSource;
const metadata = allMetadata[templateName];
// Skip validation if no metadata found
if (!metadata?.parameters) return;
if (!metadata?.['parameter.vulcan.com']) return;

const parameters = metadata.parameters;
const parameters: Parameter[] = metadata['parameter.vulcan.com'];
parameters.forEach((parameter) => {
// We only check the first value of nested parameters
const name = parameter.name.split('.')[0];
Expand Down
2 changes: 1 addition & 1 deletion packages/build/src/lib/vulcanBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
export class VulcanBuilder {
public async build(options: IBuildOptions) {
const container = new Container();
container.load(options);
await container.load(options);
const schemaParser = container.get<SchemaParser>(TYPES.SchemaParser);
const templateEngine = container.get<TemplateEngine>(
CORE_TYPES.TemplateEngine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@ it('Should add missing error codes', async () => {
};
const metadata: AllTemplateMetadata = {
'some-name': {
parameters: [],
errors: [
{
code: 'ERROR 1',
locations: [
{
lineNo: 0,
columnNo: 0,
},
],
},
],
'error.vulcan.com': {
errorCodes: [
{
code: 'ERROR 1',
locations: [
{
lineNo: 0,
columnNo: 0,
},
],
},
],
},
},
};
// Act
Expand All @@ -48,17 +49,19 @@ it('Existed error codes should be kept', async () => {
const metadata: AllTemplateMetadata = {
'some-name': {
parameters: [],
errors: [
{
code: 'ERROR 1',
locations: [
{
lineNo: 0,
columnNo: 0,
},
],
},
],
'error.vulcan.com': {
errorCodes: [
{
code: 'ERROR 1',
locations: [
{
lineNo: 0,
columnNo: 0,
},
],
},
],
},
},
};
// Act
Expand All @@ -82,7 +85,7 @@ it('Should tolerate empty error data', async () => {
const metadata: object = {
'some-name': {
parameters: [],
errors: null,
'error.vulcan.com': null,
},
};
// Act
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ it(`Should throw when any parameter hasn't be defined`, async () => {
};
const metadata: AllTemplateMetadata = {
'some-name': {
parameters: [
'parameter.vulcan.com': [
{
name: 'param1',
locations: [],
Expand Down Expand Up @@ -81,7 +81,7 @@ it('Should tolerate empty parameter data', async () => {
};
const metadata: object = {
'some-name': {
parameters: null,
'parameter.vulcan.com': null,
errors: [],
},
};
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/containers/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ export class Container {
return this.inversifyContainer.get<T>(type);
}

public load(options: ICoreOptions) {
public async load(options: ICoreOptions) {
this.inversifyContainer.load(artifactBuilderModule(options.artifact));
this.inversifyContainer.load(executorModule());
this.inversifyContainer.load(templateEngineModule(options.template));
await this.inversifyContainer.loadAsync(
templateEngineModule(options.template)
);
this.inversifyContainer.load(validatorModule());
}

Expand Down
20 changes: 16 additions & 4 deletions packages/core/src/containers/modules/executor.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { ContainerModule } from 'inversify';
import { Executor } from '@vulcan/core/template-engine';
// TODO: Should replace with a real implementation
import {
QueryBuilder,
Executor,
} from '../../lib/template-engine/built-in-extensions/query-builder/reqTagRunner';
import { TYPES } from '../types';

class MockBuilder implements QueryBuilder {
public count() {
return this;
}

public async value() {
return [];
}
}

export const executorModule = () =>
new ContainerModule((bind) => {
bind<Executor>(TYPES.Executor).toConstantValue({
// TODO: Mock value
executeQuery: async () => {
return [];
},
createBuilder: async () => new MockBuilder(),
});
});
40 changes: 24 additions & 16 deletions packages/core/src/containers/modules/templateEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,21 @@ import {
TemplateProviderType,
} from '@vulcan/core/models';
import {
ErrorExtension,
FileTemplateProvider,
NunjucksCompilerExtension,
ReqExtension,
TemplateProvider,
UniqueExtension,
InMemoryCodeLoader,
NunjucksCompiler,
Compiler,
TemplateEngine,
} from '@vulcan/core/template-engine';
import { ContainerModule, interfaces } from 'inversify';
import { AsyncContainerModule, interfaces } from 'inversify';
import { TemplateEngineOptions } from '../../options';
import * as nunjucks from 'nunjucks';
// TODO: fix the path
import { bindExtensions } from '@vulcan/core/template-engine/extension-loader';

export const templateEngineModule = (options: ITemplateEngineOptions) =>
new ContainerModule((bind) => {
new AsyncContainerModule(async (bind) => {
// Options
bind<ITemplateEngineOptions>(
TYPES.TemplateEngineInputOptions
Expand All @@ -39,16 +37,23 @@ export const templateEngineModule = (options: ITemplateEngineOptions) =>
TYPES.Factory_TemplateProvider
).toAutoNamedFactory<TemplateProvider>(TYPES.TemplateProvider);

// Extensions
bind<NunjucksCompilerExtension>(TYPES.CompilerExtension)
.to(UniqueExtension)
.inSingletonScope();
bind<NunjucksCompilerExtension>(TYPES.CompilerExtension)
.to(ErrorExtension)
.inSingletonScope();
bind<NunjucksCompilerExtension>(TYPES.CompilerExtension)
.to(ReqExtension)
.inSingletonScope();
// Compiler environment
bind<nunjucks.Environment>(TYPES.CompilerEnvironment)
.toDynamicValue((context) => {
// We only need loader in runtime
const loader = context.container.get<nunjucks.ILoader>(
TYPES.CompilerLoader
);
return new nunjucks.Environment(loader);
})
.inSingletonScope()
.whenTargetNamed('runtime');
bind<nunjucks.Environment>(TYPES.CompilerEnvironment)
.toDynamicValue(() => {
return new nunjucks.Environment();
})
.inSingletonScope()
.whenTargetNamed('compileTime');

// Loader
bind<nunjucks.ILoader>(TYPES.CompilerLoader)
Expand All @@ -62,4 +67,7 @@ export const templateEngineModule = (options: ITemplateEngineOptions) =>
bind<TemplateEngine>(TYPES.TemplateEngine)
.to(TemplateEngine)
.inSingletonScope();

// Load Extensions
await bindExtensions(bind);
});
1 change: 1 addition & 0 deletions packages/core/src/containers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const TYPES = {
Factory_TemplateProvider: Symbol.for('Factory_TemplateProvider'),
CompilerExtension: Symbol.for('CompilerExtension'),
CompilerLoader: Symbol.for('CompilerLoader'),
CompilerEnvironment: Symbol.for('CompilerEnvironment'),
Compiler: Symbol.for('Compiler'),
TemplateEngine: Symbol.for('TemplateEngine'),
TemplateEngineOptions: Symbol.for('TemplateEngineOptions'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const METADATA_NAME = 'error.vulcan.com';
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
OnAstVisit,
ProvideMetadata,
TagBuilder,
} from '../../extension-loader';
import * as nunjucks from 'nunjucks';
import { chain } from 'lodash';
import { METADATA_NAME } from './constants';

interface ErrorCode {
code: string;
lineNo: number;
columnNo: number;
}

export class ErrorTagBuilder
extends TagBuilder
implements OnAstVisit, ProvideMetadata
{
public tags = ['error'];
private errorCodes: ErrorCode[] = [];
public metadataName = METADATA_NAME;

public parse(parser: nunjucks.parser.Parser, nodes: typeof nunjucks.nodes) {
// get the tag token
const token = parser.nextToken();

const errorMessage = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(token.value);

// Add some fake nodes to the AST to indicate error position
errorMessage.addChild(
new nodes.Literal(token.lineno, token.colno, token.lineno)
);
errorMessage.addChild(
new nodes.Literal(token.lineno, token.colno, token.colno)
);

return this.createAsyncExtensionNode(errorMessage, []);
}

public onVisit(node: nunjucks.nodes.Node) {
if (node instanceof nunjucks.nodes.CallExtension) {
if (node.extName !== this.getName()) return;

const errorCodeNode = node.args.children[0];
if (!(errorCodeNode instanceof nunjucks.nodes.Literal))
throw new Error(`Expected literal, got ${errorCodeNode.typename}`);

this.errorCodes.push({
code: errorCodeNode.value,
lineNo: errorCodeNode.lineno,
columnNo: errorCodeNode.colno,
});
}
}

public getMetadata() {
return {
errorCodes: chain(this.errorCodes)
.groupBy('code')
.values()
.map((errorCodes) => ({
code: errorCodes[0].code,
locations: errorCodes.map((errorCode) => ({
lineNo: errorCode.lineNo,
columnNo: errorCode.columnNo,
})),
}))
.value(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { TagRunner, TagRunnerOptions } from '../../extension-loader';

export class ErrorTagRunner extends TagRunner {
public tags = ['error'];

public async run({ args }: TagRunnerOptions) {
const message = args[0];
const lineno = args[1];
const colno = args[2];
throw new Error(`${message} at ${lineno}:${colno}`);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ErrorTagBuilder } from './errorTagBuilder';
import { ErrorTagRunner } from './errorTagRunner';

export default [ErrorTagBuilder, ErrorTagRunner];
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import './query-builder';
import './custom-error';
import './sql-helper';
import './validator';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const FINIAL_BUILDER_NAME = 'FINAL_BUILDER';
export const METADATA_NAME = 'builder.vulcan.com';
export const EXECUTE_COMMAND_NAME = 'value';
export const EXECUTE_FILTER_NAME = 'execute';
export const REFERENCE_SEARCH_MAX_DEPTH = 100;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { FilterBuilder } from '../../extension-loader';
import { EXECUTE_FILTER_NAME } from './constants';

export class ExecutorBuilder extends FilterBuilder {
public filterName = EXECUTE_FILTER_NAME;
}
Loading