Skip to content

Commit

Permalink
feat: 配置
Browse files Browse the repository at this point in the history
close #6
  • Loading branch information
AmeroHan committed Nov 22, 2024
1 parent 74ee9be commit c580ebb
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 51 deletions.
61 changes: 59 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ tostring(acandy.Doctype.HTML) --> '<!DOCTYPE html>'
### `acandy.extend_env`

```lua
function acandy.extend_env(env: table) -> nil
function acandy.extend_env(env: table): ()
```

Extend the environment in place with `acandy.a` as `__index`, e.g., `_ENV`. This makes it possible to directly use the tag name rather than tediously type `a.`, unless there is a naming conflict with local variables or global variables.
Expand Down Expand Up @@ -516,7 +516,7 @@ print(
### `acandy.to_extended_env`

```lua
function acandy.to_extended_env(env: table) -> table
function acandy.to_extended_env(env: table): table
```

Similar to `acandy.extend_env`, but returns a new table instead of modifying the original table.
Expand Down Expand Up @@ -563,6 +563,63 @@ print(get_article())
</article>
```

## Configuration

ACandy defaults to HTML mode (currently only HTML mode, XML will be supported in the future), and has predefined some HTML void elements and raw text elements (see [config.lua](/config.lua)).

ACandy does not support modifying global configuration. To modify the configuration, create a new configured `ACandy` instance. The function signature is as follows.

```lua
type Config = {
void_elements: { [string]: true },
raw_text_elements: { [string]: true },
}
function acandy.ACandy(output_type: 'html', modify_config?: (config: Config) -> ()): table
```

The `output_type` parameter currently only accepts `'html'`. The `modify_config` parameter (optional) is a function that takes a table as a parameter and has no return value. The table passed to this function is the basis of the new configuration, and you can modify this value in the function, for example:

```lua
local acandy = require('acandy').ACandy('html', function (config)
-- add a void element
config.void_elements['my-void-element'] = true
-- remove `br` from void elements
config.void_elements.br = nil
-- add a raw text element
config.raw_text_elements['my-raw-text-element'] = true
-- remove `script` from raw text elements
config.raw_text_elements.script = nil
end)
local a = acandy.a
print(
acandy.Fragment {
a['my-void-element'],
a.br,
a['my-raw-text-element'] '< > &',
a.script 'let val = 2 > 1',
}
)
```

```html
<my-void-element>
<br></br>
<my-raw-text-element>< > &</my-raw-text-element>
<script>let val = 2 &gt; 1</script>
```

To use this configuration throughout the project, you can export the configured `ACandy` instance and import it in other files.

```lua
-- my_acandy.lua
return require('acandy').ACandy('html', function (config)
-- ...
end)

-- other files
local acandy = require('my_acandy')
```

## Concepts

### Table-like values
Expand Down
47 changes: 22 additions & 25 deletions acandy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@ local rawset = rawset
local tostring = tostring

local utils = require('.utils')
local default_void_elems, default_raw_text_elems = (function ()
local config = require('.config')
return config.void_elements, config.raw_text_elements
end)()
local classes = require('.classes')
local node_mts = classes.node_mts
local config_module = require('.config')

---@class Symbol

Expand Down Expand Up @@ -214,21 +211,23 @@ local function breadcrumb_to_string(self)
end


local function error_wrong_index()
error('attempt to access properties of a unbuilt element', 2)
end

local function error_wrong_newindex()
error('attempt to assign properties of a unbuilt element', 2)
local function ErrorEmitter(msg, level)
return function ()
error(msg, level)
end
end

local error_emitters = {
unbuilt_elem_index = ErrorEmitter('attempt to access properties of a unbuilt element', 2),
unbuilt_elem_newindex = ErrorEmitter('attempt to assign properties of a unbuilt element', 2),
built_elem_div = ErrorEmitter('attempt to perform division on a built element', 2),
}

---@param config {void_elements: {[string]: boolean}, raw_text_elements: {[string]: boolean}}?
---@param output_type 'html'
---@param modify_config fun(config: Config)?
---@nodiscard
local function ACandy(config)
config = config or {}
local void_elems = utils.list_to_bool_dict(config.void_elements or default_void_elems)
local raw_text_elems = utils.list_to_bool_dict(config.raw_text_elements or default_raw_text_elems)
local function ACandy(output_type, modify_config)
local void_elems, raw_text_elems = config_module.parse_config(output_type, modify_config)

---A BareElement is an Element without any properties except tag name, e.g.,
---`acandy.div`. It is immutable and can be cached and reused.
Expand Down Expand Up @@ -594,22 +593,20 @@ local function ACandy(config)
end,
__call = new_built_elem_from_props, --> BuiltElement
__div = elem_div, --> Breadcrumb | BuiltElement
__newindex = error_wrong_newindex,
__newindex = error_emitters.unbuilt_elem_newindex,
}
BuildingElement_mt = node_mts:register {
__tostring = elem_to_string, --> string
__call = new_built_elem_from_props, --> BuiltElement
__div = elem_div, --> Breadcrumb | BuiltElement
__index = error_wrong_index,
__newindex = error_wrong_newindex,
__index = error_emitters.unbuilt_elem_index,
__newindex = error_emitters.unbuilt_elem_newindex,
}
BuiltElement_mt = node_mts:register {
__tostring = elem_to_string, --> string
__index = get_elem_prop,
__newindex = set_elem_prop,
__div = function ()
error('attempt to perform division on a built element', 2)
end,
__div = error_emitters.built_elem_div,
}
Breadcrumb_mt = node_mts:register {
__tostring = breadcrumb_to_string, --> string
Expand All @@ -626,8 +623,8 @@ local function ACandy(config)
end
return breadcrumb_div(left, right)
end,
__index = error_wrong_index,
__newindex = error_wrong_newindex,
__index = error_emitters.unbuilt_elem_index,
__newindex = error_emitters.unbuilt_elem_newindex,
}


Expand Down Expand Up @@ -699,7 +696,7 @@ local function ACandy(config)
---Extend the environment in place with `acandy.a` as `__index`.
---@param env table the environment to be extended, e.g. `_ENV`, `_G`
function acandy.extend_env(env)
return utils.extend_env_with_elem_entry(env, a)
utils.extend_env_with_elem_entry(env, a)
end

---Return a new environment based on `env` with `acandy.a` as `__index`.
Expand Down Expand Up @@ -734,7 +731,7 @@ local acandy_module = setmt({
if not ACANDY_EXPORTED_NAMES[k] then
return nil
end
local default_acandy = ACandy()
local default_acandy = ACandy('html')
utils.copy_pairs(default_acandy, self)
assert(
default_acandy[k] ~= nil,
Expand Down
67 changes: 47 additions & 20 deletions config.lua
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
local config = {}

-- ref: https://html.spec.whatwg.org/#elements-2

config.void_elements = {
'area',
'base', 'br',
'col',
'embed',
'hr',
'img',
'input',
'link',
'meta',
'param',
'source',
'track',
'wbr',
local DEFAULT_CONFIG = {
html = {
void_elements = {
'area',
'base', 'br',
'col',
'embed',
'hr',
'img',
'input',
'link',
'meta',
'param',
'source',
'track',
'wbr',
},
raw_text_elements = {
'script', 'style',
},
},
}

config.raw_text_elements = {
'script', 'style',
}
local utils = require('.utils')

local module = {}

---ACandy configuration.
---@class Config
---@field void_elements {[string]: boolean}
---@field raw_text_elements {[string]: boolean}

---@param output_type 'html'
---@param modify_config fun(config: Config)?
---@nodiscard
function module.parse_config(output_type, modify_config)
local base_config = DEFAULT_CONFIG[output_type]
assert(base_config, 'unsupported output type: '..output_type)

local config = {
void_elements = utils.list_to_bool_dict(base_config.void_elements),
raw_text_elements = utils.list_to_bool_dict(base_config.raw_text_elements),
}
if modify_config then
modify_config(config)
end
return config.void_elements, config.raw_text_elements
end

return config
return module
65 changes: 63 additions & 2 deletions docs/README.base.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ tostring(acandy.Doctype.HTML) --> '<!DOCTYPE html>'
### `acandy.extend_env`

```lua
function acandy.extend_env(env: table) -> nil
function acandy.extend_env(env: table): ()
```

Extend the environment in place with `acandy.a` as `__index`, e.g., `_ENV`. This makes it possible to directly use the tag name rather than tediously type `a.`, unless there is a naming conflict with local variables or global variables.
Expand Down Expand Up @@ -582,7 +582,7 @@ print(
### `acandy.to_extended_env`

```lua
function acandy.to_extended_env(env: table) -> table
function acandy.to_extended_env(env: table): table
```

Similar to `acandy.extend_env`, but returns a new table instead of modifying the original table.
Expand Down Expand Up @@ -630,6 +630,67 @@ print(get_article())
</article>
```

## Configuration | 配置

ACandy defaults to HTML mode (currently only HTML mode, XML will be supported in the future), and has predefined some HTML void elements and raw text elements (see [config.lua](/config.lua)).
ACandy 默认为 HTML 模式(目前只有 HTML 模式,以后将会支持 XML),并预定义了一些 HTML 空元素和原始文本元素(见 [config.lua](/config.lua))。

ACandy does not support modifying global configuration. To modify the configuration, create a new configured `ACandy` instance. The function signature is as follows.
ACandy 不支持修改全局配置,要修改配置,请创建一个配置后的 `ACandy` 实例,其函数签名如下。

```lua
type Config = {
void_elements: { [string]: true },
raw_text_elements: { [string]: true },
}
function acandy.ACandy(output_type: 'html', modify_config?: (config: Config) -> ()): table
```

The `output_type` parameter currently only accepts `'html'`. The `modify_config` parameter (optional) is a function that takes a table as a parameter and has no return value. The table passed to this function is the basis of the new configuration, and you can modify this value in the function, for example:
其中,`output_type` 参数目前只能传入 `'html'``modify_config` 参数(可选)是一个函数,接收一个表作为参数,无返回值。传入该函数的表是新配置的基础,你可以在函数中修改这个值,例如:

```lua
local acandy = require('acandy').ACandy('html', function (config)
-- add a void element
config.void_elements['my-void-element'] = true
-- remove `br` from void elements
config.void_elements.br = nil
-- add a raw text element
config.raw_text_elements['my-raw-text-element'] = true
-- remove `script` from raw text elements
config.raw_text_elements.script = nil
end)
local a = acandy.a
print(
acandy.Fragment {
a['my-void-element'],
a.br,
a['my-raw-text-element'] '< > &',
a.script 'let val = 2 > 1',
}
)
```

```html
<my-void-element>
<br></br>
<my-raw-text-element>< > &</my-raw-text-element>
<script>let val = 2 &gt; 1</script>
```

To use this configuration throughout the project, you can export the configured `ACandy` instance and import it in other files.
要想在整个项目使用这个配置,可以导出配置后的 `ACandy` 实例,然后在其他文件中导入这个实例。

```lua
-- my_acandy.lua
return require('acandy').ACandy('html', function (config)
-- ...
end)

-- other files
local acandy = require('my_acandy')
```

## Concepts | 概念

### Table-like values | 类表值
Expand Down
Loading

0 comments on commit c580ebb

Please sign in to comment.