jsgui3-server 0.0.142 → 0.0.144

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.
Files changed (31) hide show
  1. package/docs/comprehensive-documentation.md +25 -6
  2. package/docs/configuration-reference.md +46 -11
  3. package/docs/controls-development.md +54 -26
  4. package/docs/publishers-guide.md +48 -32
  5. package/docs/troubleshooting.md +9 -8
  6. package/examples/controls/15) window, observable SSE/README.md +29 -17
  7. package/lab/README.md +19 -0
  8. package/lab/experiments/window_examples_dom_audit.js +241 -0
  9. package/lab/results/window_examples_dom_audit.json +131 -0
  10. package/lab/results/window_examples_dom_audit.md +46 -0
  11. package/package.json +7 -2
  12. package/publishers/http-observable-publisher.js +318 -125
  13. package/publishers/http-webpageorsite-publisher.js +6 -4
  14. package/resources/processors/bundlers/css-bundler.js +28 -173
  15. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +32 -20
  16. package/resources/processors/bundlers/style-bundler.js +288 -0
  17. package/resources/processors/compilers/SASS_Compiler.js +88 -0
  18. package/resources/processors/extractors/js/css_and_js/AST_Node/CSS_And_JS_From_JS_String_Using_AST_Node_Extractor.js +64 -68
  19. package/resources/website-css-resource.js +24 -20
  20. package/resources/website-javascript-resource-processor.js +17 -57
  21. package/resources/website-javascript-resource.js +17 -57
  22. package/serve-factory.js +28 -21
  23. package/server.js +13 -7
  24. package/tests/README.md +31 -3
  25. package/tests/bundlers.test.js +41 -32
  26. package/tests/content-analysis.test.js +19 -18
  27. package/tests/error-handling.test.js +13 -11
  28. package/tests/observable-sse.test.js +5 -5
  29. package/tests/sass-controls.e2e.test.js +327 -0
  30. package/tests/test-runner.js +3 -1
  31. package/tests/window-examples.puppeteer.test.js +239 -0
@@ -1,18 +1,16 @@
1
- const Bundler = require('./bundler');
2
- //const Bundle = require('./bundle');
3
- const {obs, prom_or_cb} = require('fnl');
4
- const {tof, each} = require('jsgui3-html');
5
- const fnlfs = require('fnlfs');
6
- //const browserify = require('browserify');
7
- //const babel = require('@babel/core');
8
- const stream_to_array = require('stream-to-array');
9
- const util = require('util');
10
- const Stream = require('stream');
11
- // Will put the JS together. Maybe images?
12
- const fs = require('fs');
13
- const path = require('path');
14
-
15
- const JS_AST_Node = require('../../jsbuilder/JS_AST/JS_AST_Node');
1
+ const Bundler = require('./bundler');
2
+ //const Bundle = require('./bundle');
3
+ const {obs} = require('fnl');
4
+ //const browserify = require('browserify');
5
+ //const babel = require('@babel/core');
6
+ // Will put the JS together. Maybe images?
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const CSS_And_JS_From_JS_String_Extractor = require('../extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor');
11
+ const {compile_styles} = require('./style-bundler');
12
+
13
+ const css_and_js_from_js_string_extractor = new CSS_And_JS_From_JS_String_Extractor();
16
14
 
17
15
  // Will put the JS together. Maybe images?
18
16
  // Get everything ready to serve.
@@ -53,7 +51,7 @@ const stream_html_basic_css = () => {
53
51
 
54
52
  }
55
53
 
56
- const bundle_css_from_js_str = (js_str, options = {}) => {
54
+ const bundle_css_from_js_str = (js_str, options = {}) => {
57
55
 
58
56
  //console.log('js_str.length', js_str.length);
59
57
  // Moving towards using observables as a matter of course for longer-running functions.
@@ -65,162 +63,19 @@ const bundle_css_from_js_str = (js_str, options = {}) => {
65
63
 
66
64
 
67
65
 
68
- return obs((next, complete, error) => {
69
-
70
- //console.log('js_str.length', js_str.length);
71
-
72
- // Returning a Bundle object when done could be best...?
73
-
74
- const spec = {
75
- source: js_str
76
- };
77
-
78
- // This part is kind-of slow.
79
-
80
- console.log('pre create js ast node');
81
- const js_ast_node = JS_AST_Node.from_spec(spec);
82
- console.log('post create js ast node');
83
-
84
- // Maybe a faster / different JS parser.
85
- // Or do it using regex / specialised algorithm of some sort.
86
-
87
-
88
-
89
-
90
- //console.log('!!js_ast_node', !!js_ast_node);
91
-
92
- //console.log('Object.keys(js_ast_node)', Object.keys(js_ast_node));
93
-
94
- // count all
95
-
96
- //console.log('js_ast_node.query("count all")', js_ast_node.query("count all"));
97
-
98
- //console.log('js_ast_node.query.count.all.exe()', js_ast_node.query.count.all.exe());
99
-
100
- // A filter iterate query....? filter_deep_iterate could work.
101
- // but we are looking specifically for 'ClassName.css'
102
- // .css property assignments.
103
-
104
- const ae_nodes = [];
105
-
106
-
107
- // Just assigning a template literal to .css?
108
- const css_ae_nodes = [];
109
-
110
- // How about removing those parts from the JS AST?
111
-
112
-
113
-
114
- js_ast_node.deep_iterate(node => {
115
-
116
- // Maybe this part is slow? Don't think so though.
117
-
118
- //console.log('node', node);
119
- //console.log('Object.keys(node)', Object.keys(node));
120
- //console.log('node.type_signature', node.type_signature);
121
- //console.log('node.signature', node.signature);
122
- //console.log('node.type', node.type);
123
- //console.log('node.abbreviated_type', node.abbreviated_type);
124
-
125
- if (node.type === 'AssignmentExpression') {
126
- //return true;
127
- ae_nodes.push(node);
128
- //console.log('node.source', node.source);
129
-
130
- //console.log('Object.keys(node)', Object.keys(node));
131
-
132
- //console.log('node.child_nodes.length', node.child_nodes.length);
133
-
134
- const [node_assigned_to, node_assigned] = node.child_nodes;
135
- //console.log('node_assigned_to.source', node_assigned_to.source);
136
- //console.log('node_assigned_to.type', node_assigned_to.type);
137
- //console.log('node_assigned.type', node_assigned.type);
138
-
139
- if (node_assigned.type === 'TemplateLiteral') {
140
-
141
- if (node_assigned_to.type === 'MemberExpression') {
142
-
143
- //console.log('node_assigned_to', node_assigned_to);
144
-
145
- // the last ID being .css?
146
- const last_me_child = node_assigned_to.child_nodes[node_assigned_to.child_nodes.length - 1];
147
- //console.log('last_me_child', last_me_child);
148
- //console.log('last_me_child.source', last_me_child.source);
149
-
150
- if (last_me_child.source === 'css') {
151
- css_ae_nodes.push(node);
152
- }
153
-
154
-
155
-
156
- // does it end '.css'?
157
- // break it down further?
158
-
159
- }
160
-
161
- ///console.log('node.source', node.source);
162
- //throw 'stop';
163
-
164
- }
165
-
166
- //console.log('');
167
- // look at the left part...
168
- }
169
-
170
- //throw 'stop';
171
- });
172
- //console.log('ae_nodes', ae_nodes);
173
- //console.log('ae_nodes.length', ae_nodes.length);
174
- //console.log('css_ae_nodes.length', css_ae_nodes.length);
175
-
176
- const arr_css = [];
177
-
178
- if (css_ae_nodes.length > 0) {
179
- //console.log('css_ae_nodes', css_ae_nodes);
180
-
181
- each(css_ae_nodes, css_ae_node => {
182
- //console.log('css_ae_node.source', css_ae_node.source);
183
- const tl = css_ae_node.child_nodes[1].child_nodes[0];
184
- //console.log('tl', tl);
185
- //console.log('tl.source', tl.source);
186
- arr_css.push(tl.source);
187
-
188
-
189
- })
190
- }
191
-
192
- if (arr_css.length > 0) {
193
- const str_css = arr_css.join('\n');
194
-
195
- complete(str_css);
196
- } else {
197
- complete();
198
- }
199
-
200
-
201
- // Can then do query to get all .css properties that are string templates.
202
- // is it a property of a Class object?
203
-
204
-
205
-
206
-
207
-
208
- // Need to get an AST from it....
209
- // Or could simply search (regex?) for .css = `...`?
210
-
211
-
212
-
213
-
214
- // Go through each file? Just the first?
215
-
216
- // Or should the whole bundled (browserified) JS be consulted?
217
-
218
- const [stop, pause, resume] = [() => {}, () => {}, () => {}];
219
- return [stop, pause, resume];
220
-
221
- });
222
-
223
- }
66
+ return obs((next, complete, error) => {
67
+ (async () => {
68
+ const res_extract_styles = await css_and_js_from_js_string_extractor.extract(js_str);
69
+ const {css = '', scss = '', sass = '', style_segments = []} = res_extract_styles || {};
70
+ const style_bundle = compile_styles({css, scss, sass, style_segments}, options.style || {});
71
+ complete(style_bundle.css || '');
72
+ })().catch(error);
73
+
74
+ const [stop, pause, resume] = [() => {}, () => {}, () => {}];
75
+ return [stop, pause, resume];
76
+ });
77
+
78
+ }
224
79
 
225
80
 
226
81
 
@@ -232,4 +87,4 @@ class CSS_Bundler extends Bundler {
232
87
 
233
88
  CSS_Bundler.bundle_css_from_js_str = bundle_css_from_js_str;
234
89
  CSS_Bundler.stream_html_basic_css = stream_html_basic_css;
235
- module.exports = CSS_Bundler;
90
+ module.exports = CSS_Bundler;
@@ -5,16 +5,17 @@ const Core_JS_Non_Minifying_Bundler_Using_ESBuild = require('./Core_JS_Non_Minif
5
5
  const Bundler_Using_ESBuild = require('./Bundler_Using_ESBuild');
6
6
  const {is_array} = require('lang-tools');
7
7
 
8
- const Core_JS_Single_File_Minifying_Bundler_Using_ESBuild = require('./Core_JS_Single_File_Minifying_Bundler_Using_ESBuild');
8
+ const Core_JS_Single_File_Minifying_Bundler_Using_ESBuild = require('./Core_JS_Single_File_Minifying_Bundler_Using_ESBuild');
9
9
 
10
10
  //const CSS_Extractor = require('./_Old_CSS_Extractor');
11
11
 
12
12
  // Use a different CSS extractor.
13
13
 
14
14
 
15
- const Bundle = require('../../bundle');
16
-
17
- const CSS_And_JS_From_JS_String_Extractor = require('../../../extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor');
15
+ const Bundle = require('../../bundle');
16
+
17
+ const CSS_And_JS_From_JS_String_Extractor = require('../../../extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor');
18
+ const {compile_styles} = require('../../style-bundler');
18
19
 
19
20
 
20
21
  class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
@@ -23,8 +24,10 @@ class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
23
24
 
24
25
  if (spec.debug !== undefined) this.debug = spec.debug;
25
26
 
26
- // Store bundler configuration
27
- this.bundler_config = spec.bundler || {};
27
+ // Store bundler configuration
28
+ this.bundler_config = spec.bundler || {};
29
+ const style_config = spec.style || this.bundler_config.style || {};
30
+ this.style_config = Object.assign({debug: this.debug === true}, style_config);
28
31
 
29
32
  //this.css_extractor = new CSS_Extractor();
30
33
 
@@ -46,7 +49,7 @@ class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
46
49
  }
47
50
 
48
51
  bundle(js_file_path) {
49
- const {non_minifying_bundler, css_and_js_from_js_string_extractor, minifying_js_single_file_bundler} = this;
52
+ const {non_minifying_bundler, css_and_js_from_js_string_extractor, minifying_js_single_file_bundler, style_config} = this;
50
53
 
51
54
  // Validate input
52
55
  if (typeof js_file_path !== 'string' || js_file_path.trim() === '') {
@@ -85,8 +88,17 @@ class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
85
88
  const {text} = bundle_item;
86
89
  // Then use the css and js from js extractor.
87
90
 
88
- const res_extract_css_and_js_from_js = await css_and_js_from_js_string_extractor.extract(text);
89
- const {css, js} = res_extract_css_and_js_from_js;
91
+ const res_extract_styles_and_js = await css_and_js_from_js_string_extractor.extract(text);
92
+ const {
93
+ css = '',
94
+ scss = '',
95
+ sass = '',
96
+ style_segments = [],
97
+ js = text
98
+ } = res_extract_styles_and_js || {};
99
+
100
+ const style_bundle = compile_styles({css, scss, sass, style_segments}, style_config);
101
+ const compiled_css = style_bundle.css || '';
90
102
 
91
103
  if (this.debug) {
92
104
  // Generate source maps for CSS-free JS
@@ -100,11 +112,11 @@ class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
100
112
  text: css_free_bundle_item.text
101
113
  }
102
114
  res_bundle.push(o_js_bundle_item);
103
- const o_css_bundle_item = {
104
- type: 'CSS',
105
- extension: 'css',
106
- text: css
107
- }
115
+ const o_css_bundle_item = {
116
+ type: 'CSS',
117
+ extension: 'css',
118
+ text: compiled_css
119
+ }
108
120
  res_bundle.push(o_css_bundle_item);
109
121
  next(res_bundle);
110
122
  complete(res_bundle);
@@ -128,11 +140,11 @@ class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
128
140
 
129
141
  if (is_array(minified_js) && minified_js.length === 1) {
130
142
  const minified_bundle = minified_js[0];
131
- const o_css_bundle_item = {
132
- type: 'CSS',
133
- extension: 'css',
134
- text: css
135
- }
143
+ const o_css_bundle_item = {
144
+ type: 'CSS',
145
+ extension: 'css',
146
+ text: compiled_css
147
+ }
136
148
  minified_bundle.push(o_css_bundle_item);
137
149
  next(minified_bundle);
138
150
  complete(minified_bundle);
@@ -278,4 +290,4 @@ class Advanced_JS_Bundler_Using_ESBuild extends Bundler_Using_ESBuild {
278
290
  }
279
291
 
280
292
 
281
- module.exports = Advanced_JS_Bundler_Using_ESBuild;
293
+ module.exports = Advanced_JS_Bundler_Using_ESBuild;
@@ -0,0 +1,288 @@
1
+ const SASS_Compiler = require('../compilers/SASS_Compiler');
2
+
3
+ const normalize_sources = (value) => {
4
+ if (!value) return [];
5
+ return Array.isArray(value) ? value : [value];
6
+ };
7
+
8
+ const normalize_style_segments = (value) => {
9
+ if (!value) return [];
10
+ return Array.isArray(value) ? value : [value];
11
+ };
12
+
13
+ const coerce_style_segments = (segments) => {
14
+ return normalize_style_segments(segments)
15
+ .map((segment) => {
16
+ if (!segment) return null;
17
+ if (typeof segment === 'string') {
18
+ return {type: 'css', source: segment};
19
+ }
20
+ const type_value = segment.type || segment.syntax || segment.lang;
21
+ const source_value = segment.source ?? segment.value;
22
+ if (!type_value || source_value === undefined || source_value === null) return null;
23
+ const normalized_type = typeof type_value === 'string' ? type_value.toLowerCase() : type_value;
24
+ return {type: normalized_type, source: source_value};
25
+ })
26
+ .filter(Boolean)
27
+ .filter((segment) => segment.type === 'css' || segment.type === 'scss' || segment.type === 'sass');
28
+ };
29
+
30
+ const join_sources = (sources) => {
31
+ return sources.filter(Boolean).join('\n');
32
+ };
33
+
34
+ const serialize_source_map = (source_map) => {
35
+ if (!source_map) return '';
36
+ return JSON.stringify(source_map);
37
+ };
38
+
39
+ const build_inline_source_map_comment = (source_map) => {
40
+ const source_map_json = serialize_source_map(source_map);
41
+ if (!source_map_json) return '';
42
+ const base64_map = Buffer.from(source_map_json, 'utf8').toString('base64');
43
+ return `/*# sourceMappingURL=data:application/json;base64,${base64_map} */`;
44
+ };
45
+
46
+ const get_sourcemap_config = (style_config) => {
47
+ const sourcemap_config = style_config.sourcemaps || {};
48
+ const enabled = sourcemap_config.enabled === true || (style_config.debug === true && sourcemap_config.enabled !== false);
49
+ return {
50
+ enabled,
51
+ inline: sourcemap_config.inline !== false,
52
+ include_sources: sourcemap_config.include_sources !== false
53
+ };
54
+ };
55
+
56
+ const compile_style_segments = (style_segments, style_config) => {
57
+ const scss_extra_sources = normalize_sources(style_config.scss_sources);
58
+ const sass_extra_sources = normalize_sources(style_config.sass_sources);
59
+
60
+ const load_paths = normalize_sources(style_config.load_paths);
61
+ const output_style = style_config.output_style;
62
+ const quiet_dependencies = style_config.quiet_dependencies;
63
+ const compile_css_with_sass = style_config.compile_css_with_sass !== false;
64
+ const sourcemap_config = get_sourcemap_config(style_config);
65
+
66
+ const normalized_segments = [...style_segments];
67
+ for (const source of scss_extra_sources) {
68
+ if (source) normalized_segments.push({type: 'scss', source});
69
+ }
70
+ for (const source of sass_extra_sources) {
71
+ if (source) normalized_segments.push({type: 'sass', source});
72
+ }
73
+
74
+ const has_css_segments = normalized_segments.some((segment) => segment.type === 'css');
75
+ const has_scss_segments = normalized_segments.some((segment) => segment.type === 'scss');
76
+ const has_sass_segments = normalized_segments.some((segment) => segment.type === 'sass');
77
+
78
+ const needs_sass = has_sass_segments || has_scss_segments || (compile_css_with_sass && has_css_segments);
79
+ if (!needs_sass) {
80
+ return {
81
+ css: join_sources(normalized_segments.map((segment) => segment.source)),
82
+ used_sass_toolchain: false
83
+ };
84
+ }
85
+
86
+ const sass_compiler = new SASS_Compiler({
87
+ load_paths,
88
+ output_style,
89
+ quiet_dependencies
90
+ });
91
+
92
+ const compile_individually = has_sass_segments || !compile_css_with_sass;
93
+
94
+ if (!compile_individually) {
95
+ const scss_input = join_sources(normalized_segments.map((segment) => segment.source));
96
+ const scss_result = sass_compiler.compile_scss_string(scss_input, {
97
+ source_map: sourcemap_config.enabled,
98
+ source_map_include_sources: sourcemap_config.include_sources,
99
+ return_source_map: sourcemap_config.enabled
100
+ });
101
+ const scss_output = typeof scss_result === 'string' ? scss_result : (scss_result.css || '');
102
+ const scss_source_map = typeof scss_result === 'string' ? null : (scss_result.source_map || null);
103
+
104
+ let combined_css = scss_output;
105
+ if (sourcemap_config.enabled && sourcemap_config.inline) {
106
+ const inline_comment = build_inline_source_map_comment(scss_source_map);
107
+ if (inline_comment) {
108
+ combined_css = [combined_css, inline_comment].filter(Boolean).join('\n');
109
+ }
110
+ }
111
+
112
+ return {
113
+ css: combined_css,
114
+ used_sass_toolchain: true
115
+ };
116
+ }
117
+
118
+ const compiled_chunks = [];
119
+ let compiled_segment_count = 0;
120
+ let raw_css_appended = false;
121
+ let single_source_map = null;
122
+
123
+ for (const segment of normalized_segments) {
124
+ if (!segment || !segment.source) continue;
125
+ if (segment.type === 'css' && !compile_css_with_sass) {
126
+ compiled_chunks.push(segment.source);
127
+ raw_css_appended = true;
128
+ continue;
129
+ }
130
+
131
+ if (segment.type === 'css' || segment.type === 'scss') {
132
+ const scss_result = sass_compiler.compile_scss_string(segment.source, {
133
+ source_map: sourcemap_config.enabled,
134
+ source_map_include_sources: sourcemap_config.include_sources,
135
+ return_source_map: sourcemap_config.enabled
136
+ });
137
+ const scss_output = typeof scss_result === 'string' ? scss_result : (scss_result.css || '');
138
+ const scss_source_map = typeof scss_result === 'string' ? null : (scss_result.source_map || null);
139
+ if (scss_output) compiled_chunks.push(scss_output);
140
+ compiled_segment_count += 1;
141
+ if (compiled_segment_count === 1) {
142
+ single_source_map = scss_source_map;
143
+ } else {
144
+ single_source_map = null;
145
+ }
146
+ } else if (segment.type === 'sass') {
147
+ const sass_result = sass_compiler.compile_sass_string(segment.source, {
148
+ source_map: sourcemap_config.enabled,
149
+ source_map_include_sources: sourcemap_config.include_sources,
150
+ return_source_map: sourcemap_config.enabled
151
+ });
152
+ const sass_output = typeof sass_result === 'string' ? sass_result : (sass_result.css || '');
153
+ const sass_source_map = typeof sass_result === 'string' ? null : (sass_result.source_map || null);
154
+ if (sass_output) compiled_chunks.push(sass_output);
155
+ compiled_segment_count += 1;
156
+ if (compiled_segment_count === 1) {
157
+ single_source_map = sass_source_map;
158
+ } else {
159
+ single_source_map = null;
160
+ }
161
+ }
162
+ }
163
+
164
+ let combined_css = compiled_chunks.filter(Boolean).join('\n');
165
+ if (sourcemap_config.enabled && sourcemap_config.inline && compiled_segment_count === 1 && !raw_css_appended) {
166
+ const inline_comment = build_inline_source_map_comment(single_source_map);
167
+ if (inline_comment) {
168
+ combined_css = [combined_css, inline_comment].filter(Boolean).join('\n');
169
+ }
170
+ }
171
+
172
+ return {
173
+ css: combined_css,
174
+ used_sass_toolchain: true
175
+ };
176
+ };
177
+
178
+ const compile_styles = (style_payload = {}, style_config = {}) => {
179
+ const style_segments = coerce_style_segments(style_payload.style_segments || style_payload.segments);
180
+ const has_non_css_segments = style_segments.some((segment) => segment.type !== 'css');
181
+ if (style_segments.length > 0 && has_non_css_segments) {
182
+ return compile_style_segments(style_segments, style_config);
183
+ }
184
+
185
+ const css_sources = normalize_sources(style_payload.css);
186
+ const scss_sources = normalize_sources(style_payload.scss);
187
+ const sass_sources = normalize_sources(style_payload.sass);
188
+
189
+ const scss_extra_sources = normalize_sources(style_config.scss_sources);
190
+ const sass_extra_sources = normalize_sources(style_config.sass_sources);
191
+
192
+ const load_paths = normalize_sources(style_config.load_paths);
193
+ const output_style = style_config.output_style;
194
+ const quiet_dependencies = style_config.quiet_dependencies;
195
+
196
+ const has_scss_sources = scss_sources.length > 0 || scss_extra_sources.length > 0;
197
+ const has_sass_sources = sass_sources.length > 0 || sass_extra_sources.length > 0;
198
+ const should_use_sass = has_scss_sources || has_sass_sources;
199
+ const compile_css_with_sass = style_config.compile_css_with_sass !== false;
200
+ const sourcemap_config = get_sourcemap_config(style_config);
201
+
202
+ const css_string = join_sources(css_sources);
203
+
204
+ if (!should_use_sass) {
205
+ return {
206
+ css: css_string,
207
+ used_sass_toolchain: false
208
+ };
209
+ }
210
+
211
+ const sass_compiler = new SASS_Compiler({
212
+ load_paths,
213
+ output_style,
214
+ quiet_dependencies
215
+ });
216
+
217
+ let scss_output = '';
218
+ let sass_output = '';
219
+ let scss_source_map = null;
220
+ let sass_source_map = null;
221
+
222
+ if (has_scss_sources || (compile_css_with_sass && css_string)) {
223
+ const scss_sources_to_compile = [];
224
+ if (compile_css_with_sass && css_string) scss_sources_to_compile.push(css_string);
225
+ scss_sources_to_compile.push(...scss_sources, ...scss_extra_sources);
226
+
227
+ const scss_input = join_sources(scss_sources_to_compile);
228
+ if (scss_input) {
229
+ const scss_result = sass_compiler.compile_scss_string(scss_input, {
230
+ source_map: sourcemap_config.enabled,
231
+ source_map_include_sources: sourcemap_config.include_sources,
232
+ return_source_map: sourcemap_config.enabled
233
+ });
234
+ if (typeof scss_result === 'string') {
235
+ scss_output = scss_result;
236
+ } else {
237
+ scss_output = scss_result.css || '';
238
+ scss_source_map = scss_result.source_map || null;
239
+ }
240
+ }
241
+ }
242
+
243
+ if (has_sass_sources) {
244
+ const sass_sources_to_compile = [...sass_sources, ...sass_extra_sources];
245
+ const sass_input = join_sources(sass_sources_to_compile);
246
+ if (sass_input) {
247
+ const sass_result = sass_compiler.compile_sass_string(sass_input, {
248
+ source_map: sourcemap_config.enabled,
249
+ source_map_include_sources: sourcemap_config.include_sources,
250
+ return_source_map: sourcemap_config.enabled
251
+ });
252
+ if (typeof sass_result === 'string') {
253
+ sass_output = sass_result;
254
+ } else {
255
+ sass_output = sass_result.css || '';
256
+ sass_source_map = sass_result.source_map || null;
257
+ }
258
+ }
259
+ }
260
+
261
+ let combined_css = [scss_output, sass_output].filter(Boolean).join('\n');
262
+ const raw_css_appended = !compile_css_with_sass && css_string;
263
+ if (raw_css_appended) {
264
+ combined_css = [css_string, combined_css].filter(Boolean).join('\n');
265
+ }
266
+
267
+ if (sourcemap_config.enabled && sourcemap_config.inline) {
268
+ const has_scss_output = Boolean(scss_output);
269
+ const has_sass_output = Boolean(sass_output);
270
+ const can_inline_map = !raw_css_appended && ((has_scss_output && !has_sass_output) || (!has_scss_output && has_sass_output));
271
+ if (can_inline_map) {
272
+ const selected_map = has_scss_output ? scss_source_map : sass_source_map;
273
+ const inline_comment = build_inline_source_map_comment(selected_map);
274
+ if (inline_comment) {
275
+ combined_css = [combined_css, inline_comment].filter(Boolean).join('\n');
276
+ }
277
+ }
278
+ }
279
+
280
+ return {
281
+ css: combined_css,
282
+ used_sass_toolchain: true
283
+ };
284
+ };
285
+
286
+ module.exports = {
287
+ compile_styles
288
+ };