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: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ COPY . /app

RUN lua5.1 tests/harness/metadata.lua \
&& timeout 60s lua5.1 tests/harness/ast-bindings.lua \
&& timeout 60s lua5.1 tests/harness/parser-sources.lua \
&& timeout 60s lua5.1 tests/harness/step-sources.lua \
&& timeout 60s lua5.1 tests/harness/source-maps.lua \
&& timeout 60s python3 tests/harness/source-maps.py \
&& timeout 60s lua5.1 tests/harness/numbers-to-expressions.lua \
&& timeout 60s lua5.1 tests/harness/cff-arity.lua \
&& timeout 60s lua5.1 tests/harness/cff-native.lua \
Expand Down
60 changes: 60 additions & 0 deletions doc/advanced/how-the-pipeline-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,63 @@ After all steps finish, Prometheus renames identifiers using:
## Logging

Pipeline emits informational logs for each phase and step timing, including output size relative to source.

## Source maps

Source map generation is disabled by default. Set `SourceMap = true` in a config
to make `Pipeline:apply` return the generated code and map table. Original
source text is embedded by default; set `SourceMapIncludeSources = false` to
omit it.

```lua
local Prometheus = require("src.prometheus")
local config = {
LuaVersion = "Lua51",
SourceMap = true,
SourceMapIncludeSources = true,
Steps = {},
}

local pipeline = Prometheus.Pipeline:fromConfig(config)
local code, map = pipeline:apply(source, "src/main.lua")
map.file = "main.obfuscated.lua" -- Generated file basename
local mapJson = Prometheus.SourceMap.encode(map)
```

`Prometheus.SourceMap.decode(mapJson)` parses and validates JSON and returns a
map table. `Prometheus.SourceMap.lookup(map, generatedLine)` returns the
original source path, one-based line, and embedded source text when present.
Lookup uses the first mapped segment on that exact generated line; lines with
no mapped segment return `nil`. Source maps retain approximate line locations
where transformations combine or rewrite syntax.

`Prometheus.Traceback.format(traceback, map, mapPath)` rewrites matching Lua
and Luau frames and appends source excerpts around mapped locations. If the map
does not embed source text, it reads source files relative to `mapPath`,
including `sourceRoot` when present. Set `map.file` to the generated output
basename so tracebacks can be matched reliably; the CLI sets this field from
`--out` automatically. When source maps are enabled in a CLI config, the CLI
writes `<output-file>.map` by default; `--source-map <path>` overrides it.

## Parser source locations

`Parser:parse(code, pathOrSourceRecord)` attaches a `sourceSpan` to AST nodes.
The second argument can be a path string or a source record table containing
`path` and `content`; omitting it gives the input a unique internal snippet
label. A span contains a `source` record, `startLine`, `startColumn`, `endLine`,
`endColumn`, `startOffset`, and `endOffset`. Lines and byte columns are
one-based; byte offsets are zero-based and the end offset is exclusive.

```lua
local Parser = require("src.prometheus.parser")
local parser = Parser:new({ LuaVersion = "Lua51" })
local ast = parser:parse(source, {
path = "src/main.lua",
content = source,
})
local firstStatementSpan = ast.body.statements[1].sourceSpan
```

Generated snippets use internal paths such as
`prometheus-internal://snippet/1`; these labels distinguish generated source
from user files and can include the snippet text for traceback excerpts.
37 changes: 37 additions & 0 deletions doc/guides/cli-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,45 @@ Enable pretty output:
prometheus-lua --preset Minify --pretty ./src/main.lua
```

Generate a source map with embedded source text:

```bash
prometheus-lua --preset Medium --out ./output.lua --source-map ./output.lua.map ./src/main.lua
```

Use the map to rewrite a traceback saved in a file:

```bash
prometheus-lua trace --map ./output.lua.map ./traceback.txt
```

`trace` also accepts `-` as the traceback path to read from standard input:

```bash
lua ./output.lua 2>&1 | prometheus-lua trace --map ./output.lua.map -
```

The map embeds the original source by default. To omit it, add
`--source-map-no-sources`; `trace` will then look for source files relative to
the map file and its optional `sourceRoot`. The trace formatter appends source
excerpts around resolved locations. It recognizes Lua `file:line:` locations
and Luau `Script 'file', Line N` locations, while leaving C frames and paths
that do not match the map's generated file unchanged.

If a custom config sets `SourceMap = true`, the CLI writes `<output-file>.map`
by default. Passing `--source-map <path>` overrides that sidecar path.

## Notes

- Unknown `--...` options are ignored with a warning.
- If no config/preset is passed, Prometheus falls back to `Minify`.
- `update` command uses the official installer script from GitHub.
- Source map line mappings are approximate because generated and original
code do not have a one-to-one line relationship. Compact and pretty output
can have different unmapped lines; the formatter only maps exact generated
lines that have a source map segment.
- VM implementation lines use explicit `prometheus-internal://VM/...` source
labels in the displayed trace. Generated lines without mappings retain their
generated location.
- `AntiTamper` is skipped when source maps are enabled, with a warning, because
its generated checks are incompatible with source map output.
40 changes: 40 additions & 0 deletions doc/reference/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
| `update` | Runs official installer script to install latest release |
| `--version`, `-v` | Prints version (`PROMETHEUS_LUA_VERSION` or `dev`) |
| `--help`, `-h`, `help` | Prints CLI help |
| `trace --map <file.map> <traceback.txt>` | Rewrites generated Lua locations using a source map; use `-` instead of a file to read the traceback from standard input |

## Obfuscation options

Expand All @@ -15,6 +16,8 @@
| `--preset` | `--p` | `<name>` | Use built-in preset by name |
| `--config` | `--c` | `<file>` | Load config Lua file |
| `--out` | `--o` | `<file>` | Output file path |
| `--source-map` | - | `<file.map>` | Write a source map to the specified path; enables source maps for this invocation |
| `--source-map-no-sources` | - | none | Omit embedded original source text from the generated map |
| `--Lua51` | - | none | Force Lua 5.1 conventions |
| `--LuaU` | - | none | Force LuaU conventions |
| `--pretty` | - | none | Pretty-print generated output |
Expand All @@ -26,3 +29,40 @@
- First non-option argument is treated as input file.
- A second non-option argument raises an error.
- Unknown options are ignored with a warning.

## Source maps and tracebacks

`--source-map <file.map>` writes a version 3 source map for the generated output.
If source maps are enabled through a config and this option is omitted, the CLI
writes `<output-file>.map`; the explicit option selects a different path.
Original source text is embedded by default so `trace` can show excerpts without
access to the original files. `--source-map-no-sources` omits that text; the
trace command then looks for the original source relative to the map file,
including any `sourceRoot` recorded in the map. The CLI stores relative source
paths relative to the map file so maps remain usable when saved in a subfolder.
When embedded-source output is enabled, source text that is not valid UTF-8 is
omitted from `sourcesContent` as `null` and the CLI logs a warning. With
`--source-map-no-sources`, no embedded-source warning is emitted.

For example, save a traceback in a file and translate it with:

```bash
prometheus-lua trace --map ./output.lua.map ./traceback.txt
```

To read the traceback from a pipe or the terminal, pass `-`:

```bash
some-lua-runtime ./output.lua 2>&1 | prometheus-lua trace --map ./output.lua.map -
```

Trace mapping uses the first mapped segment on each exact generated line. It
does not infer mappings for lines without a segment, so compact and pretty
output can have approximate coverage. C frames and unrelated file paths are
left as written. Excerpts show two source lines on either side of each mapped
line where available; missing source files are reported in the output.
VM implementation lines can appear under explicit `prometheus-internal://VM/...`
labels, and generated lines without a mapping remain in the traceback as
generated locations. `AntiTamper` is skipped with a warning when source maps
are enabled because its generated checks are incompatible with source map
output.
9 changes: 9 additions & 0 deletions doc/reference/config-object.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ Prometheus config table fields:
| --- | --- | --- | --- |
| `LuaVersion` | string | `"Lua51"` (in `fromConfig`) | Target parser/unparser conventions (`Lua51` or `LuaU`) |
| `PrettyPrint` | boolean | `false` | Pretty output mode |
| `SourceMap` | boolean | `false` | Generate a source map and return it as the second result from `Pipeline:apply` |
| `SourceMapIncludeSources` | boolean | `true` | Embed original source text in generated maps when `SourceMap` is enabled |
| `VarNamePrefix` | string | `""` | Prefix for generated variable names |
| `NameGenerator` | string | `"MangledShuffled"` | Name generator key |
| `Seed` | number | `0` | RNG seed; `<=0` means generated seed |
| `Steps` | table | `{}` | Ordered step list |

With `SourceMap = true`, `Pipeline:apply(code, filename)` returns the generated
code and a source map table. `SourceMapIncludeSources` defaults to `true`; set
it to `false` to keep source text out of the map. Maps without embedded sources
can still be used when the original files are available relative to the map
file. In the CLI, a config with `SourceMap = true` writes `<output-file>.map`
unless `--source-map <path>` selects another location.

## Steps format

```lua
Expand Down
Loading
Loading