Commit 242eaa88 authored by David Sveningsson's avatar David Sveningsson

feat(meta): allow plugins to add copyable metadata

parent c6fa5466
Pipeline #114287975 passed with stages
in 10 minutes and 29 seconds
......@@ -277,3 +277,53 @@ switch (meta.myProperty) {
default: /* ... */
}
```
### Copyable metadata
Plugins leveraging usage of `loadMeta` for advanced handling of metadata loading must explicitly mark the copyable properties as `copyable`:
```js
module.exports = {
elementSchema: {
properties: {
foo: {
copyable: true,
},
bar: {
copyable: false,
},
},
},
};
```
Given these two properties only `foo` will be copied (loaded) onto the element when using `loadMeta`:
```js
module.exports = {
"my-element": {
foo: "original",
bar: "original",
},
"my-element:slot": {
foo: "overwritten",
bar: "overwritten",
},
};
```
```js
function processElement(node) {
const meta = this.getMetaFor("my-element:slot");
node.loadMeta(meta);
}
```
The resulting metadata will now be:
```json
{
"foo": "overwritten",
"bar": "original"
}
```
......@@ -5,7 +5,7 @@ import path from "path";
import { Source } from "../context";
import { NestedError, SchemaValidationError } from "../error";
import { MetaTable } from "../meta";
import { MetaDataTable } from "../meta/element";
import { MetaCopyableProperty, MetaDataTable } from "../meta/element";
import { Plugin } from "../plugin";
import schema from "../schema/config.json";
import { TransformContext, Transformer, TRANSFORMER_API } from "../transform";
......@@ -174,6 +174,7 @@ export class Config {
/* load plugins */
this.plugins = this.loadPlugins(this.config.plugins || []);
this.configurations = this.loadConfigurations(this.plugins);
this.extendMeta(this.plugins);
/* process extended configs */
for (const extend of this.config.extends) {
......@@ -394,6 +395,25 @@ export class Config {
return configs;
}
private extendMeta(plugins: LoadedPlugin[]): void {
for (const plugin of plugins) {
if (!plugin.elementSchema) {
continue;
}
const { properties } = plugin.elementSchema;
if (!properties) {
continue;
}
for (const [key, schema] of Object.entries(properties)) {
if (schema.copyable && !MetaCopyableProperty.includes(key)) {
MetaCopyableProperty.push(key);
}
}
}
}
/**
* Transform a source.
*
......
import { Config } from "../config";
import { ConfigError } from "../config/error";
import { Source } from "../context";
import { HtmlElement } from "../dom";
import { Engine } from "../engine";
import { EventHandler } from "../event";
import { Parser } from "../parser";
......@@ -236,6 +237,45 @@ describe("Plugin", () => {
});
expect(() => config.getMetaTable()).not.toThrow();
});
it("should support copyable properties", () => {
mockPlugin.elementSchema = {
properties: {
foo: {
copyable: true,
},
bar: {
copyable: false,
},
},
};
config = Config.fromObject({
plugins: ["mock-plugin"],
elements: [
{
"my-element": {
foo: "original",
bar: "original",
},
"my-element:real": {
foo: "copied",
bar: "copied",
},
},
],
});
const metaTable = config.getMetaTable();
const a = metaTable.getMetaFor("my-element");
const b = metaTable.getMetaFor("my-element:real");
const node = new HtmlElement("my-element", null, null, a);
node.loadMeta(b);
expect(node.meta).toEqual({
tagName: "my-element",
foo: "copied" /* foo is marked for copying */,
bar: "original" /* bar is not marked for copying */,
void: false /* autofilled */,
});
});
});
describe("callbacks", () => {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment