pugkit 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,11 +9,6 @@
9
9
  </a>
10
10
  </p>
11
11
 
12
- ## About
13
-
14
- pugkitは静的サイト制作に特化したビルドツールです。
15
- 納品向きの綺麗なHTMLと、ファイル構成に制約のないアセットファイルを出力可能です。
16
-
17
12
  ## How To Use
18
13
 
19
14
  ```sh
@@ -39,6 +34,34 @@ $ touch ./src/index.pug
39
34
  | `pugkit build` | 本番ビルド |
40
35
  | `pugkit sprite` | SVGスプライト生成 |
41
36
 
37
+ ## Directory Structure
38
+
39
+ ```
40
+ project-root/
41
+ ├── src/ # ソースファイル
42
+ │ ├── *.pug
43
+ │ ├── *.scss
44
+ │ ├── *.ts
45
+ │ ├── *.js
46
+ │ ├── *.jpg
47
+ │ ├── *.png
48
+ │ └── *.svg
49
+ ├── public/ # 静的ファイル
50
+ │ ├── ogp.jpg
51
+ │ └── favicon.ico
52
+ ├── dist/ # ビルド出力先
53
+ └── pugkit.config.mjs # ビルド設定ファイル
54
+ ```
55
+
56
+ ### File Naming Rules
57
+
58
+ `_`(アンダースコア)で始まるファイル・ディレクトリはビルド対象外です。それ以外のファイルは `src/` 配下のディレクトリ構成を維持したまま `dist/` に出力されます。
59
+
60
+ ```
61
+ src/foo/style.scss → dist/foo/style.css
62
+ src/foo/bar/script.js → dist/foo/bar/script.js
63
+ ```
64
+
42
65
  ## Configuration
43
66
 
44
67
  プロジェクトルートに`pugkit.config.mjs`を配置することで、ビルド設定をカスタマイズできます。
@@ -70,7 +93,7 @@ export default defineConfig({
70
93
  | `server.port` | 開発サーバーのポート番号 | `number` | `5555` |
71
94
  | `server.host` | 開発サーバーのホスト | `string` | `'localhost'` |
72
95
  | `server.startPath` | サーバー起動時に開くパス | `string` | `'/'` |
73
- | `server.open` | サーバー起動時にブラウザを開く | `boolean` | `false` |
96
+ | `build.clean` | ビルド前に `dist/` をクリーンするか(`false` にすると他リソースと共存可能) | `boolean` | `true` |
74
97
  | `build.imageOptimization` | 画像最適化の方式 | `'webp'` \| `'compress'` \| `false` | `'webp'` |
75
98
  | `build.imageOptions.webp` | WebP変換オプション([Sharp WebP options](https://sharp.pixelplumbing.com/api-output#webp)) | `object` | - |
76
99
  | `build.imageOptions.jpeg` | JPEG圧縮オプション([Sharp JPEG options](https://sharp.pixelplumbing.com/api-output#jpeg)) | `object` | - |
@@ -176,9 +199,13 @@ npm install --save-dev typescript
176
199
  - `'compress'` - 元の形式を維持したまま圧縮
177
200
  - `false` - 最適化を無効化
178
201
 
202
+ ### SVG Optimization
203
+
204
+ `icons/`以外に配置した SVG ファイルはSVGOで自動最適化されて出力されます。
205
+
179
206
  ### SVG Sprite
180
207
 
181
- `src/` 配下の `icons/` ディレクトリに配置したSVGを1つのスプライトファイルにまとめます。
208
+ `src/`配下の`icons/`ディレクトリに配置したSVGを1つのスプライトファイルにまとめます。
182
209
 
183
210
  ```
184
211
  src/assets/icons/arrow.svg → dist/assets/icons.svg#arrow
@@ -191,10 +218,6 @@ src/assets/icons/arrow.svg → dist/assets/icons.svg#arrow
191
218
  - SVG ファイル名がそのまま `<symbol id>` になります
192
219
  - `fill` / `stroke` は自動的に `currentColor` に変換されます
193
220
 
194
- ### SVG Optimization
195
-
196
- `icons/` 以外に配置した SVG ファイルは SVGO で自動最適化されて出力されます。
197
-
198
221
  ### Public Directory
199
222
 
200
223
  `public/` に置いたファイルはそのまま `dist/` のルートにコピーされます。faviconやOGP画像など最適化不要なファイルの置き場として使用します。
@@ -208,34 +231,6 @@ src/assets/icons/arrow.svg → dist/assets/icons.svg#arrow
208
231
  | CSS | minify済み | expanded + ソースマップ |
209
232
  | JS | minify済み・`console.*` 削除 | ソースマップ・`console.*` 保持 |
210
233
 
211
- ### File Naming Rules
212
-
213
- `_`(アンダースコア)で始まるファイル・ディレクトリはビルド対象外です。それ以外のファイルは `src/` 配下のディレクトリ構成を維持したまま `dist/` に出力されます。
214
-
215
- ```
216
- src/foo/style.scss → dist/foo/style.css
217
- src/foo/bar/script.js → dist/foo/bar/script.js
218
- ```
219
-
220
- ## Directory Structure
221
-
222
- ```
223
- project-root/
224
- ├── src/ # ソースファイル
225
- │ ├── *.pug
226
- │ ├── *.scss
227
- │ ├── *.ts
228
- │ ├── *.js
229
- │ ├── *.jpg
230
- │ ├── *.png
231
- │ └── *.svg
232
- ├── public/ # 静的ファイル
233
- │ ├── ogp.jpg
234
- │ └── favicon.ico
235
- ├── dist/ # ビルド出力先
236
- └── pugkit.config.mjs # ビルド設定ファイル
237
- ```
238
-
239
234
  ## Tech Stack
240
235
 
241
236
  - [Pug](https://pugjs.org/) - HTMLテンプレートエンジン
@@ -8,6 +8,7 @@ export const defaultConfig = {
8
8
  startPath: '/'
9
9
  },
10
10
  build: {
11
+ clean: true,
11
12
  imageOptimization: 'webp',
12
13
  imageOptions: {
13
14
  webp: {
package/config/main.mjs CHANGED
@@ -25,6 +25,7 @@ function mergeConfig(defaults, user) {
25
25
  build: {
26
26
  ...defaults.build,
27
27
  ...(user.build || {}),
28
+ clean: user.build?.clean !== undefined ? user.build.clean : defaults.build.clean,
28
29
  imageOptions: {
29
30
  webp: { ...defaults.build.imageOptions.webp, ...(user.build?.imageOptions?.webp || {}) },
30
31
  jpeg: { ...defaults.build.imageOptions.jpeg, ...(user.build?.imageOptions?.jpeg || {}) },
@@ -11,20 +11,11 @@ export function createGlobPatterns(srcPath) {
11
11
  ignore: ['**/*.d.ts', '**/node_modules/**']
12
12
  },
13
13
  images: {
14
- optimize: [
15
- `${srcPath}/**/*.{png,jpg,jpeg}`,
16
- `!${srcPath}/**/sprites_*/*`,
17
- `!${srcPath}/**/_inline*/*`,
18
- `!${srcPath}/**/icons*/*`
19
- ],
20
- webp: {
21
- src: [`${srcPath}/**/*.{png,jpg,jpeg,gif}`],
22
- ignore: [`!${srcPath}/**/favicons/*`, `!${srcPath}/**/ogp.{png,jpg}`]
23
- }
14
+ optimize: [`${srcPath}/**/*.{png,jpg,jpeg}`, `!${srcPath}/**/icons/*`],
15
+ webp: [`${srcPath}/**/*.{png,jpg,jpeg,gif}`, `!${srcPath}/**/icons/*`]
24
16
  },
25
17
  svg: {
26
- src: [`${srcPath}/**/*.svg`],
27
- ignore: [`!${srcPath}/**/sprites_*/*`, `!${srcPath}/**/_inline*/*`, `!${srcPath}/**/icons*/*`]
18
+ src: [`${srcPath}/**/*.svg`, `!${srcPath}/**/icons/*`]
28
19
  }
29
20
  }
30
21
  }
package/core/builder.mjs CHANGED
@@ -34,11 +34,17 @@ export class Builder {
34
34
  const { context } = this
35
35
  const startTime = Date.now()
36
36
 
37
+ const shouldClean = context.config.build.clean
38
+
37
39
  logger.info('build', `Building in ${context.mode} mode`)
38
40
 
39
41
  try {
40
42
  // 1. クリーンアップ
41
- await this.clean()
43
+ if (shouldClean) {
44
+ await this.clean()
45
+ } else {
46
+ logger.info('build', 'Skipping clean (clean: false)')
47
+ }
42
48
 
43
49
  // 2. 並列ビルド(軽量タスク + スプライト)
44
50
  const parallelTasks = []
package/core/context.mjs CHANGED
@@ -9,6 +9,8 @@ export class BuildContext {
9
9
  this.mode = mode
10
10
  this.cache = new CacheManager(mode)
11
11
  this.graph = new DependencyGraph()
12
+ this.sassGraph = new DependencyGraph()
13
+ this.scriptGraph = new DependencyGraph()
12
14
 
13
15
  this.paths = {
14
16
  root: config.root,
package/core/graph.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 依存関係グラフ
3
- * Pugのパーシャル依存を管理
3
+ * Pug・Sass・Script のパーシャル依存を管理
4
4
  */
5
5
  export class DependencyGraph {
6
6
  constructor() {
package/core/watcher.mjs CHANGED
@@ -25,9 +25,18 @@ class FileWatcher {
25
25
 
26
26
  // 初回ビルド(依存関係グラフ構築のため)
27
27
  logger.info('watch', 'Building initial dependency graph...')
28
+
29
+ const initialTasks = []
28
30
  if (this.context.taskRegistry?.pug) {
29
- await this.context.taskRegistry.pug(this.context)
31
+ initialTasks.push(this.context.taskRegistry.pug(this.context))
32
+ }
33
+ if (this.context.taskRegistry?.sass) {
34
+ initialTasks.push(this.context.taskRegistry.sass(this.context))
30
35
  }
36
+ if (this.context.taskRegistry?.script) {
37
+ initialTasks.push(this.context.taskRegistry.script(this.context))
38
+ }
39
+ await Promise.all(initialTasks)
31
40
 
32
41
  this.watcher = chokidar
33
42
  .watch([paths.src, paths.public], {
@@ -55,6 +64,9 @@ class FileWatcher {
55
64
 
56
65
  handleAdd(filePath) {
57
66
  if (this.isPublic(filePath)) return this.onPublicChange(filePath, 'add')
67
+ if (filePath.endsWith('.pug')) return this.onPugChange(filePath)
68
+ if (filePath.endsWith('.scss')) return this.onSassChange(filePath)
69
+ if (this.isScript(filePath)) return this.onScriptChange(filePath)
58
70
  if (filePath.endsWith('.svg') && !this.isIcons(filePath)) return this.onSvgChange(filePath, 'add')
59
71
  if (/\.(jpg|jpeg|png|gif)$/i.test(filePath)) return this.onImageChange(filePath, 'add')
60
72
  }
@@ -122,7 +134,7 @@ class FileWatcher {
122
134
  const relPath = relative(this.context.paths.src, filePath)
123
135
  logger.info('change', `sass: ${relPath}`)
124
136
  try {
125
- if (this.context.taskRegistry?.sass) await this.context.taskRegistry.sass(this.context)
137
+ if (this.context.taskRegistry?.sass) await this.context.taskRegistry.sass(this.context, { files: [filePath] })
126
138
  this.injectCSS()
127
139
  } catch (error) {
128
140
  logger.error('watch', `Sass build failed: ${error.message}`)
@@ -130,8 +142,9 @@ class FileWatcher {
130
142
  }
131
143
 
132
144
  async onSassUnlink(filePath) {
133
- const { paths } = this.context
145
+ const { paths, sassGraph } = this.context
134
146
  const relPath = relative(paths.src, filePath)
147
+ sassGraph.clearDependencies(filePath)
135
148
  if (basename(filePath).startsWith('_')) {
136
149
  logger.info('unlink', relPath)
137
150
  return
@@ -146,7 +159,7 @@ class FileWatcher {
146
159
  const relPath = relative(this.context.paths.src, filePath)
147
160
  logger.info('change', `script: ${relPath}`)
148
161
  try {
149
- if (this.context.taskRegistry?.script) await this.context.taskRegistry.script(this.context)
162
+ if (this.context.taskRegistry?.script) await this.context.taskRegistry.script(this.context, { files: [filePath] })
150
163
  this.reload()
151
164
  } catch (error) {
152
165
  logger.error('watch', `Script build failed: ${error.message}`)
@@ -154,8 +167,9 @@ class FileWatcher {
154
167
  }
155
168
 
156
169
  async onScriptUnlink(filePath) {
157
- const { paths } = this.context
170
+ const { paths, scriptGraph } = this.context
158
171
  const relPath = relative(paths.src, filePath)
172
+ scriptGraph.clearDependencies(filePath)
159
173
  if (basename(filePath).startsWith('_')) {
160
174
  logger.info('unlink', relPath)
161
175
  return
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pugkit",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A build tool for Pug-based projects",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -49,9 +49,9 @@
49
49
  "esbuild": "^0.25.5",
50
50
  "glob": "^13.0.6",
51
51
  "image-size": "^2.0.2",
52
+ "js-beautify": "^1.15.4",
52
53
  "picocolors": "^1.1.1",
53
54
  "postcss": "^8.4.49",
54
- "prettier": "^3.8.0",
55
55
  "pug": "^3.0.3",
56
56
  "sass": "^1.89.2",
57
57
  "sharp": "^0.34.2",
package/tasks/pug.mjs CHANGED
@@ -69,7 +69,7 @@ async function processFile(filePath, context) {
69
69
  const imageInfo = createImageInfoHelper(filePath, paths, logger, config)
70
70
 
71
71
  const html = template({ Builder: builderVars, imageSize, imageInfo })
72
- const formatted = await formatHtml(html)
72
+ const formatted = formatHtml(html)
73
73
  await generatePage(filePath, formatted, paths)
74
74
  } catch (error) {
75
75
  logger.error('pug', `Failed: ${basename(filePath)} - ${error.message}`)
package/tasks/sass.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { glob } from 'glob'
2
2
  import { readFile, writeFile } from 'node:fs/promises'
3
3
  import { relative, resolve, basename, extname } from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
4
5
  import * as sass from 'sass'
5
6
  import postcss from 'postcss'
6
7
  import autoprefixer from 'autoprefixer'
@@ -12,36 +13,64 @@ import { ensureFileDir } from '../utils/file.mjs'
12
13
  * Sassビルドタスク
13
14
  */
14
15
  export async function sassTask(context, options = {}) {
15
- const { paths, config, isProduction } = context
16
+ const { paths, config, isProduction, isDevelopment, sassGraph, cache } = context
16
17
 
17
18
  // debugモードはdevモード時のみ有効
18
19
  const isDebugMode = !isProduction && config.debug
19
20
 
20
- // 1. ビルド対象ファイルの取得
21
- const scssFiles = await glob('**/[^_]*.scss', {
21
+ // 1. ビルド対象ファイルの取得(非パーシャル)
22
+ const allEntryFiles = await glob('**/[^_]*.scss', {
22
23
  cwd: paths.src,
23
24
  absolute: true,
24
25
  ignore: ['**/_*.scss']
25
26
  })
26
27
 
27
- if (scssFiles.length === 0) {
28
+ if (allEntryFiles.length === 0) {
28
29
  logger.skip('sass', 'No files to build')
29
30
  return
30
31
  }
31
32
 
32
- logger.info('sass', `Building ${scssFiles.length} file(s)`)
33
+ // 2. dev モードでのインクリメンタルビルド
34
+ let filesToBuild = allEntryFiles
35
+
36
+ if (isDevelopment && options.files?.length > 0) {
37
+ const changedFile = options.files[0]
38
+ const isPartial = basename(changedFile).startsWith('_')
39
+
40
+ if (isPartial) {
41
+ // パーシャル変更 → 依存グラフから影響を受けるエントリファイルを特定
42
+ const affected = sassGraph.getAffectedParents(changedFile)
43
+ filesToBuild = affected.filter(f => allEntryFiles.includes(f))
44
+
45
+ if (filesToBuild.length === 0) {
46
+ // グラフにまだ情報がない場合はフルビルド
47
+ filesToBuild = allEntryFiles
48
+ } else {
49
+ logger.info('sass', `Partial changed, rebuilding ${filesToBuild.length} affected file(s)`)
50
+ }
51
+ } else {
52
+ // 非パーシャル変更 → そのファイルだけリビルド
53
+ filesToBuild = allEntryFiles.filter(f => f === changedFile)
54
+ if (filesToBuild.length === 0) {
55
+ logger.skip('sass', 'Changed file is not a build target')
56
+ return
57
+ }
58
+ }
59
+ }
60
+
61
+ logger.info('sass', `Building ${filesToBuild.length} file(s)`)
33
62
 
34
- // 2. 並列コンパイル
35
- await Promise.all(scssFiles.map(file => compileSassFile(file, context, isDebugMode)))
63
+ // 3. 並列コンパイル
64
+ await Promise.all(filesToBuild.map(file => compileSassFile(file, context, isDebugMode)))
36
65
 
37
- logger.success('sass', `Built ${scssFiles.length} file(s)`)
66
+ logger.success('sass', `Built ${filesToBuild.length} file(s)`)
38
67
  }
39
68
 
40
69
  /**
41
70
  * 個別Sassファイルのコンパイル
42
71
  */
43
72
  async function compileSassFile(filePath, context, isDebugMode) {
44
- const { paths, config, isProduction } = context
73
+ const { paths, config, isProduction, sassGraph } = context
45
74
 
46
75
  try {
47
76
  // Sassコンパイル
@@ -55,6 +84,19 @@ async function compileSassFile(filePath, context, isDebugMode) {
55
84
  sourceMapIncludeSources: isDebugMode
56
85
  })
57
86
 
87
+ // 依存グラフを更新(loadedUrls からパーシャルの依存関係を構築)
88
+ sassGraph.clearDependencies(filePath)
89
+ if (result.loadedUrls) {
90
+ for (const url of result.loadedUrls) {
91
+ if (url.protocol === 'file:') {
92
+ const depPath = fileURLToPath(url)
93
+ if (depPath !== filePath) {
94
+ sassGraph.addDependency(filePath, depPath)
95
+ }
96
+ }
97
+ }
98
+ }
99
+
58
100
  let css = result.css
59
101
 
60
102
  // PostCSS処理
package/tasks/script.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { glob } from 'glob'
2
- import { resolve, relative, dirname } from 'node:path'
2
+ import { resolve, relative, dirname, basename } from 'node:path'
3
3
  import * as esbuild from 'esbuild'
4
4
  import { logger } from '../utils/logger.mjs'
5
5
  import { ensureDir } from '../utils/file.mjs'
@@ -8,29 +8,53 @@ import { ensureDir } from '../utils/file.mjs'
8
8
  * esbuild(TypeScript/JavaScript)ビルドタスク
9
9
  */
10
10
  export async function scriptTask(context, options = {}) {
11
- const { paths, isProduction, config } = context
11
+ const { paths, isProduction, isDevelopment, config, scriptGraph } = context
12
12
 
13
13
  // 1. ビルド対象ファイルの取得
14
- const scriptFiles = await glob('**/[^_]*.{ts,js}', {
14
+ const allEntryFiles = await glob('**/[^_]*.{ts,js}', {
15
15
  cwd: paths.src,
16
16
  absolute: true,
17
17
  ignore: ['**/*.d.ts', '**/node_modules/**']
18
18
  })
19
19
 
20
- if (scriptFiles.length === 0) {
20
+ if (allEntryFiles.length === 0) {
21
21
  logger.skip('script', 'No files to build')
22
22
  return
23
23
  }
24
24
 
25
- logger.info('script', `Building ${scriptFiles.length} file(s)`)
25
+ // 2. dev モードでのインクリメンタルビルド
26
+ let filesToBuild = allEntryFiles
27
+
28
+ if (isDevelopment && options.files?.length > 0) {
29
+ const changedFile = options.files[0]
30
+ const isPartial = basename(changedFile).startsWith('_')
31
+
32
+ if (isPartial) {
33
+ // パーシャル変更 → 依存グラフから影響を受けるエントリファイルを特定
34
+ const affected = scriptGraph.getAffectedParents(changedFile)
35
+ filesToBuild = affected.filter(f => allEntryFiles.includes(f))
36
+
37
+ if (filesToBuild.length === 0) {
38
+ // グラフにまだ情報がない場合はフルビルド
39
+ filesToBuild = allEntryFiles
40
+ } else {
41
+ logger.info('script', `Partial changed, rebuilding ${filesToBuild.length} affected file(s)`)
42
+ }
43
+ } else if (allEntryFiles.includes(changedFile)) {
44
+ // 非パーシャルのエントリファイル → そのファイルだけリビルド
45
+ filesToBuild = [changedFile]
46
+ }
47
+ }
48
+
49
+ logger.info('script', `Building ${filesToBuild.length} file(s)`)
26
50
 
27
51
  // debugモードはdevモード時のみ有効
28
52
  const isDebugMode = !isProduction && config.debug
29
53
 
30
54
  try {
31
- // 2. esbuild設定
55
+ // 3. esbuild設定
32
56
  const esbuildConfig = {
33
- entryPoints: scriptFiles,
57
+ entryPoints: filesToBuild,
34
58
  outdir: paths.dist,
35
59
  outbase: paths.src,
36
60
  bundle: true,
@@ -41,7 +65,7 @@ export async function scriptTask(context, options = {}) {
41
65
  write: true,
42
66
  sourcemap: isDebugMode,
43
67
  minify: false,
44
- metafile: false,
68
+ metafile: true,
45
69
  logLevel: 'error',
46
70
  keepNames: false,
47
71
  external: [],
@@ -57,7 +81,7 @@ export async function scriptTask(context, options = {}) {
57
81
  esbuildConfig.drop = ['console', 'debugger']
58
82
  }
59
83
 
60
- // 3. ビルド実行
84
+ // 4. ビルド実行
61
85
  await ensureDir(paths.dist)
62
86
  const result = await esbuild.build(esbuildConfig)
63
87
 
@@ -65,7 +89,24 @@ export async function scriptTask(context, options = {}) {
65
89
  throw new Error(`esbuild errors: ${result.errors.length}`)
66
90
  }
67
91
 
68
- logger.success('script', `Built ${scriptFiles.length} file(s)`)
92
+ // 5. 依存グラフを更新(metafile から依存関係を構築)
93
+ if (result.metafile) {
94
+ for (const [output, meta] of Object.entries(result.metafile.outputs)) {
95
+ if (!meta.entryPoint) continue
96
+ const entryPath = resolve(paths.root, meta.entryPoint)
97
+
98
+ scriptGraph.clearDependencies(entryPath)
99
+
100
+ for (const inputPath of Object.keys(meta.inputs)) {
101
+ const absInputPath = resolve(paths.root, inputPath)
102
+ if (absInputPath !== entryPath) {
103
+ scriptGraph.addDependency(entryPath, absInputPath)
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ logger.success('script', `Built ${filesToBuild.length} file(s)`)
69
110
  } catch (error) {
70
111
  logger.error('script', error.message)
71
112
  throw error
@@ -1,14 +1,18 @@
1
- import prettier from 'prettier'
1
+ import pkg from 'js-beautify'
2
+ const { html: beautifyHtml } = pkg
2
3
 
3
- export async function formatHtml(html, options = {}) {
4
+ export function formatHtml(html, options = {}) {
4
5
  const cleaned = html.replace(/[\u200B-\u200D\uFEFF]/g, '')
5
6
 
6
- return prettier.format(cleaned, {
7
- parser: 'html',
8
- printWidth: options.printWidth || 100_000,
9
- tabWidth: options.tabWidth || 2,
10
- useTabs: options.useTabs || false,
11
- htmlWhitespaceSensitivity: 'ignore',
12
- singleAttributePerLine: false
7
+ return beautifyHtml(cleaned, {
8
+ indent_size: options.tabWidth || 2,
9
+ indent_with_tabs: options.useTabs || false,
10
+ max_preserve_newlines: 1,
11
+ preserve_newlines: false,
12
+ end_with_newline: true,
13
+ extra_liners: [],
14
+ wrap_line_length: 0,
15
+ inline: [],
16
+ content_unformatted: ['script', 'style', 'pre']
13
17
  })
14
18
  }