@rws-framework/client 2.12.0 → 2.13.1

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 (56) hide show
  1. package/builder/vite/index.ts +5 -0
  2. package/builder/vite/rws.vite.config.ts +50 -0
  3. package/{webpack → builder/webpack}/index.js +3 -1
  4. package/{webpack → builder/webpack}/loaders/rws_fast_html_loader.js +8 -0
  5. package/{webpack → builder/webpack}/loaders/rws_fast_scss_loader.js +8 -1
  6. package/{webpack → builder/webpack}/loaders/rws_fast_ts_loader.js +1 -1
  7. package/{rws.webpack.config.js → builder/webpack/rws.webpack.config.js} +18 -13
  8. package/bun.lockb +0 -0
  9. package/cfg/build_steps/vite/_build_config.ts +106 -0
  10. package/cfg/build_steps/vite/_env_defines.ts +17 -0
  11. package/cfg/build_steps/vite/_loaders.ts +185 -0
  12. package/cfg/build_steps/vite/index.ts +3 -0
  13. package/cfg/build_steps/vite/loaders/html.ts +12 -0
  14. package/cfg/build_steps/vite/loaders/index.ts +9 -0
  15. package/cfg/build_steps/vite/loaders/loader.type.ts +28 -0
  16. package/cfg/build_steps/vite/loaders/scss.ts +33 -0
  17. package/cfg/build_steps/vite/loaders/ts.ts +313 -0
  18. package/cfg/build_steps/vite/rws_scss_plugin.ts +60 -0
  19. package/cfg/build_steps/vite/scss/_compiler.ts +95 -0
  20. package/cfg/build_steps/vite/scss/_fonts.ts +81 -0
  21. package/cfg/build_steps/vite/scss/_fs.ts +82 -0
  22. package/cfg/build_steps/vite/scss/_import.ts +185 -0
  23. package/cfg/build_steps/vite/types.ts +8 -0
  24. package/cfg/build_steps/webpack/_actions.js +0 -0
  25. package/cfg/build_steps/webpack/_build_config.js +0 -0
  26. package/cfg/build_steps/webpack/_component_handling.js +0 -0
  27. package/cfg/build_steps/webpack/_dev_servers.js +0 -0
  28. package/cfg/build_steps/webpack/_env_defines.js +2 -7
  29. package/cfg/build_steps/webpack/_loaders.js +0 -6
  30. package/cfg/build_steps/webpack/_plugins.js +0 -0
  31. package/cfg/build_steps/webpack/_webpack_config.js +6 -1
  32. package/package.json +11 -9
  33. package/src/client/config.ts +2 -2
  34. package/src/client.ts +1 -1
  35. package/src/components/_component.ts +4 -2
  36. package/src/components/_container.ts +2 -6
  37. package/src/components/_decorator.ts +1 -1
  38. package/src/components/_definitions.ts +0 -1
  39. package/src/components/_event_handling.ts +1 -1
  40. package/src/index.ts +60 -70
  41. package/src/services/ApiService.ts +1 -8
  42. package/src/services/_service.ts +2 -2
  43. package/src/styles/_grid.scss +16 -8
  44. package/src/styles/_scrollbars.scss +1 -0
  45. package/src/styles/includes.scss +0 -1
  46. package/src/types/IRWSConfig.ts +2 -2
  47. package/src/types/IRWSPlugin.ts +3 -5
  48. /package/{webpack → builder/webpack}/after/copy.js +0 -0
  49. /package/{webpack → builder/webpack}/after/sw.js +0 -0
  50. /package/{webpack → builder/webpack}/loaders/ts/html_error.js +0 -0
  51. /package/{webpack → builder/webpack}/rws_scss_plugin.js +0 -0
  52. /package/{webpack → builder/webpack}/rws_webpack_plugin.js +0 -0
  53. /package/{webpack → builder/webpack}/scss/_compiler.js +0 -0
  54. /package/{webpack → builder/webpack}/scss/_fonts.js +0 -0
  55. /package/{webpack → builder/webpack}/scss/_fs.js +0 -0
  56. /package/{webpack → builder/webpack}/scss/_import.js +0 -0
@@ -0,0 +1,313 @@
1
+ import { IRWSViteLoader, TSLoaderParams } from "./loader.type";
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ import chalk from 'chalk';
6
+ import md5 from 'md5';
7
+ import JSON5 from 'json5'
8
+ import { RWSScssPlugin } from "../rws_scss_plugin";
9
+
10
+ interface DecoratorArgsData {
11
+ template?: string;
12
+ styles?: string;
13
+ ignorePackaging?: boolean;
14
+ debugPackaging?: boolean;
15
+ fastElementOptions?: any;
16
+ }
17
+
18
+ interface ViewDecoratorData {
19
+ decoratorArgs?: DecoratorArgsData;
20
+ tagName: string;
21
+ className: string;
22
+ classNamePrefix?: string | null; // Added this field
23
+ }
24
+
25
+ interface DecoratorExtract {
26
+ viewDecoratorData?: ViewDecoratorData | null;
27
+ replacedDecorator: string;
28
+ }
29
+
30
+ // Cache manager - możesz to wydzielić do osobnego pliku
31
+ class CacheManager {
32
+ private cache: Map<string, string> = new Map();
33
+ private customOptions: any;
34
+
35
+ constructor(customOptions: any = null) {
36
+ this.customOptions = customOptions;
37
+ }
38
+
39
+ getCachedItem(filePath: string, hash: string): string | null {
40
+ const key = `${filePath}:${hash}`;
41
+ return this.cache.get(key) || null;
42
+ }
43
+
44
+ cacheItem(filePath: string, content: string, originalContent: string): void {
45
+ const key = `${filePath}:${md5(originalContent)}`;
46
+ this.cache.set(key, content);
47
+ }
48
+ }
49
+
50
+ // Helper functions - też możesz wydzielić
51
+ class LoadersHelper {
52
+ static extractRWSViewArgs(content: string, noReplace = false): DecoratorExtract | null {
53
+ const viewReg = /@RWSView\(\s*["']([^"']+)["'](?:\s*,\s*([\s\S]*?))?\s*\)\s*(.*?\s+)?class\s+([a-zA-Z0-9_-]+)\s+extends\s+RWSViewComponent/gm;
54
+
55
+ let m: RegExpExecArray | null = null;;
56
+ let tagName: string | null = null;
57
+ let className: string | null = null;
58
+ let classNamePrefix: string | null = null;
59
+ let decoratorArgs: DecoratorArgsData | null = null;
60
+
61
+ const _defaultRWSLoaderOptions = {
62
+ templatePath: 'template.html',
63
+ stylesPath: 'styles.scss',
64
+ fastOptions: { shadowOptions: { mode: 'open' } }
65
+ }
66
+
67
+ while ((m = viewReg.exec(content)) !== null) {
68
+ if (m.index === viewReg.lastIndex) {
69
+ viewReg.lastIndex++;
70
+ }
71
+
72
+ m.forEach((match, groupIndex) => {
73
+ if (groupIndex === 1) {
74
+ tagName = match;
75
+ }
76
+
77
+ if (groupIndex === 2) {
78
+ if (match) {
79
+ try {
80
+ decoratorArgs = JSON5.parse(match);
81
+ } catch(e){
82
+ console.log(chalk.red('Decorator options parse error: ') + e.message + '\n Problematic line:');
83
+ console.log(`
84
+ @RWSView(${tagName}, ${match})
85
+ `);
86
+ console.log(chalk.yellowBright(`Decorator options failed to parse for "${tagName}" component.`) + ' { decoratorArgs } defaulting to null.');
87
+ console.log(match);
88
+
89
+ throw new Error('Failed parsing @RWSView')
90
+ }
91
+ }
92
+ }
93
+
94
+ if (groupIndex === 3) {
95
+ if(match){
96
+ classNamePrefix = match;
97
+ }
98
+ }
99
+
100
+ if (groupIndex === 4) {
101
+ className = match;
102
+ }
103
+ });
104
+ }
105
+
106
+ if(!tagName || !className){
107
+ return null;
108
+ }
109
+
110
+ let processedContent = content;
111
+
112
+ let fastOptions = _defaultRWSLoaderOptions.fastOptions;
113
+ decoratorArgs = decoratorArgs as unknown as DecoratorArgsData;
114
+ if (decoratorArgs?.fastElementOptions) {
115
+ fastOptions = decoratorArgs.fastElementOptions;
116
+ }
117
+
118
+ let replacedDecorator: string | null = null;
119
+
120
+ if(!noReplace){
121
+ const [addedParamDefs, addedParams] = this._extractRWSViewDefs(fastOptions, decoratorArgs || {});
122
+ const replacedViewDecoratorContent = processedContent.replace(
123
+ viewReg,
124
+ `@RWSView('$1', null, { template: rwsTemplate, styles${addedParams.length ? ', options: {' + (addedParams.join(', ')) + '}' : ''} })\n$3class $4 extends RWSViewComponent `
125
+ );
126
+
127
+ replacedDecorator = `${addedParamDefs.join('\n')}\n${replacedViewDecoratorContent}`;
128
+ }
129
+
130
+ return {
131
+ viewDecoratorData: {
132
+ tagName,
133
+ className,
134
+ classNamePrefix,
135
+ decoratorArgs
136
+ },
137
+ replacedDecorator: replacedDecorator || '' // Ensure it's never null
138
+ }
139
+ }
140
+
141
+ private static _extractRWSViewDefs(fastOptions = {}, decoratorArgs = {})
142
+ {
143
+ const addedParamDefs: string[] = [];
144
+ const addedParams: string[] = [];
145
+
146
+ for (const key in fastOptions){
147
+ addedParamDefs.push(`const ${key} = ${JSON.stringify(fastOptions[key])};`);
148
+ addedParams.push(key);
149
+ }
150
+
151
+ return [addedParamDefs, addedParams];
152
+ }
153
+
154
+ static async getStyles(plugin: RWSScssPlugin, filePath: string, addDependency: (path: string) => void, templateExists: boolean, stylesPath?: string, isDev?: boolean): Promise<string> {
155
+ if(!stylesPath){
156
+ stylesPath = 'styles/layout.scss';
157
+ }
158
+
159
+ let styles = 'const styles: null = null;'
160
+ const stylesFilePath = path.dirname(filePath) + '/' + stylesPath;
161
+
162
+ if (fs.existsSync(stylesFilePath)) {
163
+ const scsscontent = fs.readFileSync(stylesFilePath, 'utf-8');
164
+
165
+ const codeData = await plugin.compileScssCode(scsscontent, path.dirname(filePath) + '/styles');
166
+ const cssCode = codeData.code;
167
+
168
+ styles = isDev ? `import './${stylesPath}';\n` : '';
169
+
170
+ if (!templateExists) {
171
+ styles += `import { css } from '@microsoft/fast-element';\n`;
172
+ }
173
+ styles += `const styles = ${templateExists ? 'T.' : ''}css\`${cssCode}\`;\n`;
174
+
175
+ addDependency(path.dirname(filePath) + '/' + stylesPath);
176
+ }
177
+
178
+ return styles;
179
+ }
180
+
181
+ static async getTemplate(filePath: string, addDependency: (path: string) => void, templateName?: string, isDev?: boolean) {
182
+ if(!templateName){
183
+ templateName = 'template';
184
+ }
185
+ const templatePath = path.dirname(filePath) + `/${templateName}.html`;
186
+ let htmlFastImports: string | null = null;
187
+ const templateExists = fs.existsSync(templatePath);
188
+ let template = 'const rwsTemplate: null = null;';
189
+
190
+ if (templateExists) {
191
+ const templateContent = fs.readFileSync(templatePath, 'utf-8').replace(/<!--[\s\S]*?-->/g, '');
192
+ htmlFastImports = `import * as T from '@microsoft/fast-element';\nimport './${templateName}.html';\n`;
193
+ template = `
194
+ //@ts-ignore
195
+ let rwsTemplate: any = T.html\`${templateContent}\`;
196
+ `;
197
+ addDependency(templatePath);
198
+ }
199
+
200
+ return [template, htmlFastImports, templateExists];
201
+ }
202
+ }
203
+
204
+ // Główny loader
205
+ const loader: IRWSViteLoader<TSLoaderParams> = async (params: TSLoaderParams) => {
206
+
207
+ const cacheManager = new CacheManager();
208
+
209
+ return {
210
+ name: 'rws-typescript',
211
+ enforce: 'pre',
212
+ async transform(code: string, id: string) {
213
+
214
+ if (!id.endsWith('.ts')) return null;
215
+ if (id.endsWith('.debug.ts') || id.endsWith('.d.ts')) return null;
216
+ if (id.includes('node_modules') && !id.includes('@rws-framework')) return null;
217
+
218
+ let processedContent: string = code;
219
+ const isDev: boolean = params.dev;
220
+ let isIgnored: boolean = false;
221
+ let isDebugged: boolean = false;
222
+
223
+ try {
224
+ const decoratorExtract: DecoratorExtract | null = await LoadersHelper.extractRWSViewArgs(processedContent);
225
+ const decoratorData: ViewDecoratorData | null = decoratorExtract?.viewDecoratorData || null;
226
+
227
+ const cachedCode: string = processedContent;
228
+ // const cachedTS = cacheManager.getCachedItem(id, md5(cachedCode as string));
229
+
230
+ // if (cachedTS) {
231
+ // return {
232
+ // code: cachedTS,
233
+ // map: null
234
+ // };
235
+ // }
236
+
237
+ if (!decoratorData) {
238
+ return null;
239
+ }
240
+
241
+ let templateName: string | null = decoratorData.decoratorArgs?.template || null;
242
+ let stylesPath = decoratorData.decoratorArgs?.styles || null;
243
+ isIgnored = decoratorData.decoratorArgs?.ignorePackaging || false;
244
+ isDebugged = decoratorData.decoratorArgs?.debugPackaging || false;
245
+
246
+ const tagName = decoratorData.tagName;
247
+ const className = decoratorData.className;
248
+
249
+ const defaultTemplatePath = path.resolve(path.dirname(id), 'template.html');
250
+ const defaultStylesPath = path.resolve(path.dirname(id), 'styles', 'layout.scss');
251
+
252
+ if(!templateName && fs.existsSync(defaultTemplatePath)){
253
+ templateName ='template';
254
+ }
255
+
256
+ if(!stylesPath && fs.existsSync(defaultStylesPath)){
257
+ stylesPath ='styles/layout.scss';
258
+ }
259
+ console.log({stylesPath, templateName, tagName})
260
+
261
+ if (tagName && templateName && stylesPath) {
262
+ const [template, htmlFastImports, templateExists] = await LoadersHelper.getTemplate(
263
+ id,
264
+ (path) => this.addWatchFile(path),
265
+ templateName,
266
+ isDev
267
+ );
268
+
269
+ const styles = await LoadersHelper.getStyles(
270
+ params.scssPlugin,
271
+ id,
272
+ (path) => this.addWatchFile(path),
273
+ templateExists as boolean,
274
+ stylesPath,
275
+ isDev
276
+ );
277
+
278
+ console.log({styles})
279
+
280
+ if (className && decoratorExtract?.replacedDecorator) {
281
+ processedContent = `${template}\n${styles}\n${decoratorExtract.replacedDecorator}`;
282
+ }
283
+
284
+ processedContent = `${htmlFastImports ? htmlFastImports + '\n' : ''}${processedContent}`;
285
+ }
286
+
287
+ const debugTsPath = id.replace('.ts', '.debug.ts');
288
+
289
+ if (fs.existsSync(debugTsPath)) {
290
+ fs.unlinkSync(debugTsPath);
291
+ }
292
+
293
+ if (isDebugged) {
294
+ console.log(chalk.red('[RWS BUILD] Debugging into: ' + debugTsPath));
295
+ fs.writeFileSync(debugTsPath, processedContent);
296
+ }
297
+
298
+ cacheManager.cacheItem(id, processedContent, cachedCode);
299
+
300
+ return {
301
+ code: processedContent,
302
+ map: null
303
+ };
304
+ } catch (e) {
305
+ console.log(chalk.red('RWS Typescript loader error:'));
306
+ console.error(e);
307
+ throw new Error('RWS Build failed on: ' + id);
308
+ }
309
+ }
310
+ };
311
+ };
312
+
313
+ export default loader;
@@ -0,0 +1,60 @@
1
+ import path from 'path';
2
+ import { rwsPath } from '@rws-framework/console';
3
+
4
+ import _scss_compiler_builder from './scss/_compiler';
5
+ import _scss_import_builder from './scss/_import';
6
+
7
+ import _scss_fs_builder from './scss/_fs';
8
+
9
+ type PluginParams = { autoCompile: string[] };
10
+
11
+ class RWSScssPlugin {
12
+ protected autoCompile: string[] = [];
13
+ protected node_modules_dir: (fileDir: string) => void;
14
+
15
+ private _scss_import: any;
16
+ private _scss_fs: any;
17
+ private _scss_compiler: any;
18
+
19
+ constructor(params: PluginParams = { autoCompile: [] }) {
20
+ this.node_modules_dir = (fileDir) => path.relative(fileDir, rwsPath.findRootWorkspacePath(process.cwd())) + '/node_modules/'
21
+ this._scss_import = _scss_import_builder(this);
22
+ this._scss_fs = _scss_fs_builder(this);
23
+ this._scss_compiler = _scss_compiler_builder(this);
24
+
25
+ if (!!params.autoCompile && params.autoCompile.length > 0) {
26
+ this.autoCompile = params.autoCompile;
27
+ }
28
+
29
+ for (let index in this.autoCompile) {
30
+ const sassFile = this.autoCompile[index];
31
+ this.compileFile(sassFile);
32
+ }
33
+ }
34
+
35
+
36
+ apply(compiler) {
37
+ const _self = this;
38
+
39
+ return;
40
+ }
41
+
42
+ async compileFile(scssPath): Promise<{ code: string, dependencies: string[]}>
43
+ {
44
+ scssPath = this._scss_import.processImportPath(scssPath, path.dirname(scssPath))
45
+ let scssCode = this._scss_fs.getCodeFromFile(scssPath);
46
+ return await this._scss_compiler.compileScssCode(scssCode, path.dirname(scssPath), null, scssPath);
47
+ }
48
+
49
+ async compileScssCode(scssCode: string, scssPath: string): Promise<{ code: string, dependencies: string[]}>
50
+ {
51
+ return await this._scss_compiler.compileScssCode(scssCode, scssPath, null, scssPath);
52
+ }
53
+
54
+ writeCssFile(scssFilePath: string, cssContent: string): string
55
+ {
56
+ return this._scss_fs.writeCssFile(scssFilePath, cssContent);
57
+ }
58
+ }
59
+
60
+ export {RWSScssPlugin};
@@ -0,0 +1,95 @@
1
+ import sass from 'sass-embedded';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import emojiRegex from 'emoji-regex';
5
+
6
+ import _scss_fonts_builder from './_fonts';
7
+ let _scss_fonts: any = null;
8
+ import _scss_import_builder from './_import';
9
+ let _scss_import: any = null;
10
+
11
+ async function compileScssCode(scssCode: string, fileRootDir: string, createFile:boolean = false, filePath: string | null = null, minify: boolean = false): Promise<{
12
+ code: string,
13
+ dependencies: string[]
14
+ }> {
15
+ _scss_fonts = _scss_fonts_builder(this);
16
+ _scss_import = _scss_import_builder(this);
17
+
18
+ const [scssImports] = _scss_import.extractScssImports(scssCode, fileRootDir);
19
+ const dependencies = scssImports.map((item) => item[2]);
20
+
21
+ if (scssImports && scssImports.length) {
22
+ scssCode = _scss_import.replaceImports(_scss_import.processImports(scssImports, fileRootDir), scssCode);
23
+ }
24
+
25
+ const uses = _scss_import.extractScssUses(scssCode)[0];
26
+ let scssUses = '';
27
+ uses.forEach(scssUse => {
28
+ const useLine = scssUse[1];
29
+ if(scssCode.indexOf(useLine) === -1){
30
+ scssUses += useLine + '\n';
31
+ scssCode = scssCode.replace(useLine + '\n', '');
32
+ }
33
+ });
34
+
35
+ scssCode = removeComments(scssUses + scssCode);
36
+
37
+ try {
38
+
39
+ const result: sass.CompileResult = await sass.compileStringAsync(scssCode, {
40
+ loadPaths: [fileRootDir],
41
+ style: minify ? "compressed" : "expanded",
42
+ sourceMap: false
43
+ });
44
+
45
+ let compiledCode = result.css.toString();
46
+
47
+ compiledCode = _scss_fonts.replaceFontUrlWithBase64(compiledCode);
48
+ compiledCode = replaceEmojisWithQuestionMark(compiledCode, fileRootDir);
49
+ return { code: compiledCode, dependencies };
50
+ } catch (err) {
51
+ console.error('SASS Error in', fileRootDir);
52
+ console.error(err);
53
+ throw err;
54
+ }
55
+ }
56
+
57
+ function checkForImporterType(_module, checkTypeExt) {
58
+ let importingFileExtension = '';
59
+ if (_module && _module.issuer && _module.issuer.resource) {
60
+ importingFileExtension = path.extname(_module.issuer.resource);
61
+ if (importingFileExtension === ('.' + checkTypeExt)) {
62
+ return true;
63
+ }
64
+ } else {
65
+ return false;
66
+ }
67
+ return false
68
+ }
69
+
70
+ function replaceEmojisWithQuestionMark(code, componentDir) {
71
+ const regex = emojiRegex();
72
+ let hasEmoji = false;
73
+ const result = code.replace(regex, (match) => {
74
+ hasEmoji = true;
75
+ return '?';
76
+ });
77
+ if (hasEmoji) {
78
+ console.log(chalk.yellow(`Emojis in css detected and replaced with "?" in "${path.dirname(componentDir)}" component`));
79
+ }
80
+ return result;
81
+ }
82
+
83
+ function removeComments(code) {
84
+ code = code.replace(/\/\/.*$/gm, '');
85
+ code = code.replace(/\/\*[\s\S]*?\*\//g, '');
86
+ code = code.replace(/^\s*$(?:\r\n?|\n)/gm, '');
87
+ return code;
88
+ }
89
+
90
+ export default function(element) {
91
+ return {
92
+ checkForImporterType: checkForImporterType.bind(element),
93
+ compileScssCode: compileScssCode.bind(element)
94
+ };
95
+ };
@@ -0,0 +1,81 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const FONT_REGEX = /url\(['"]?(.+?\.(woff|woff2|eot|ttf|otf))['"]?\)/gm;
4
+
5
+ import _scss_import_builder from './_import';
6
+ let _scss_import: any = null;
7
+
8
+ function hasFontEmbeds(css) {
9
+ return FONT_REGEX.test(css);
10
+ }
11
+
12
+ function embedFontsInCss(css, cssFilePath) {
13
+ let match;
14
+
15
+ while ((match = FONT_REGEX.exec(css)) !== null) {
16
+ const fontPath = match[1];
17
+ const absoluteFontPath = path.resolve(path.dirname(cssFilePath), fontPath);
18
+
19
+ if (fs.existsSync(absoluteFontPath)) {
20
+ const fontData = fs.readFileSync(absoluteFontPath);
21
+ const base64Font = fontData.toString('base64');
22
+ const fontMimeType = getFontMimeType(path.extname(absoluteFontPath));
23
+ const fontDataURL = `data:${fontMimeType};base64,${base64Font}`;
24
+
25
+ css = css.replace(new RegExp(match[0], 'g'), `url(${fontDataURL})`);
26
+ }
27
+ }
28
+
29
+ return css;
30
+ }
31
+
32
+ function getFontMimeType(extension) {
33
+ switch (extension) {
34
+ case '.woff': return 'font/woff';
35
+ case '.woff2': return 'font/woff2';
36
+ case '.eot': return 'application/vnd.ms-fontobject';
37
+ case '.ttf': return 'font/ttf';
38
+ case '.otf': return 'font/otf';
39
+ default: return 'application/octet-stream';
40
+ }
41
+ }
42
+
43
+ function convertFontToBase64(fontPath) {
44
+ return fs.readFileSync(fontPath, { encoding: 'base64' });
45
+ }
46
+
47
+ function replaceFontUrlWithBase64(cssContent) {
48
+ const fontFaceRegex = /@font-face\s*\{[^}]*\}/g;
49
+ let fontFaces = [...cssContent.matchAll(fontFaceRegex)];
50
+ _scss_import = _scss_import_builder(this);
51
+
52
+ for (const fontFace of fontFaces) {
53
+ const fontFaceContent = fontFace[0];
54
+ const urlRegex = /url\((['"]?)([^)'"]+)(\1)\)/g;
55
+ let match;
56
+
57
+ let modifiedFontFaceContent = fontFaceContent;
58
+
59
+ while ((match = urlRegex.exec(fontFaceContent)) !== null) {
60
+ // Create a promise to convert each font to Base64 and replace in CSS
61
+ const base64 = convertFontToBase64(_scss_import.processImportPath(match[2], null, true));
62
+ const base64Font = `data:font/woff2;base64,${base64}`;
63
+
64
+ modifiedFontFaceContent = modifiedFontFaceContent.replace(match[2], base64Font);
65
+ }
66
+
67
+ cssContent = cssContent.replace(fontFaceContent, modifiedFontFaceContent)
68
+ };
69
+
70
+ return cssContent;
71
+ }
72
+
73
+ export default function(element) {
74
+ return {
75
+ hasFontEmbeds: hasFontEmbeds.bind(element),
76
+ embedFontsInCss: embedFontsInCss.bind(element),
77
+ getFontMimeType: getFontMimeType.bind(element),
78
+ convertFontToBase64: convertFontToBase64.bind(element),
79
+ replaceFontUrlWithBase64: replaceFontUrlWithBase64.bind(element)
80
+ };
81
+ };
@@ -0,0 +1,82 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ import _scss_import from './_import';
5
+ const _COMPILE_DIR_NAME = 'compiled';
6
+
7
+
8
+ function writeCssFile(scssFilePath, cssContent) {
9
+ const cssFilePath = scssFilePath.replace('.scss', '.css');
10
+ let endCssFilePath = cssFilePath.split('/');
11
+ let endCssDirVars: string[] = [...endCssFilePath];
12
+ endCssDirVars[endCssDirVars.length - 1] = `${_COMPILE_DIR_NAME}`;
13
+ const endCssDir: string = endCssDirVars.join('/');
14
+
15
+ if (!fs.existsSync(endCssDir)) {
16
+ fs.mkdirSync(endCssDir);
17
+ }
18
+
19
+ endCssFilePath[endCssFilePath.length - 1] = `${_COMPILE_DIR_NAME}/` + endCssFilePath[endCssFilePath.length - 1];
20
+ endCssFilePath = endCssFilePath.join('/');
21
+
22
+ fs.writeFile(endCssFilePath, cssContent, () => {});
23
+ console.log('Saved external CSS file in: ' + endCssFilePath);
24
+ }
25
+
26
+ function readSCSSFilesFromDirectory(dirPath) {
27
+ let scssFiles: string[] = [];
28
+
29
+ try {
30
+ const files = fs.readdirSync(dirPath);
31
+
32
+ files.forEach(file => {
33
+ const filePath: string = path.join(dirPath, file);
34
+ const stat = fs.statSync(filePath);
35
+
36
+ if (stat.isFile() && path.extname(file) === '.scss') {
37
+ scssFiles.push(filePath);
38
+ } else if (stat.isDirectory()) {
39
+ scssFiles = scssFiles.concat(readSCSSFilesFromDirectory(filePath));
40
+ }
41
+ });
42
+ } catch (e) {
43
+ console.error(`Failed to read directory ${dirPath}:`, e);
44
+ }
45
+
46
+ return scssFiles;
47
+ };
48
+
49
+
50
+ function getCodeFromFile(filePath) {
51
+ filePath = filePath.replace('//', '/');
52
+ if (!fs.existsSync(filePath)) {
53
+ const processedImportPath = _scss_import(this).processImportPath(filePath, path.dirname(filePath));
54
+ if (!fs.existsSync(processedImportPath)) {
55
+ throw new Error(`SCSS loader: File path "${filePath}" was not found.`);
56
+ }
57
+
58
+ filePath = processedImportPath;
59
+ }
60
+
61
+ if (filePath[filePath.length - 1] === '/' && fs.statSync(filePath).isDirectory()) {
62
+ let collectedCode = '';
63
+
64
+ readSCSSFilesFromDirectory(filePath).forEach(scssPath => {
65
+ collectedCode += fs.readFileSync(scssPath, 'utf-8');
66
+ });
67
+
68
+ return collectedCode;
69
+ } else if (fs.statSync(filePath).isDirectory()) {
70
+ throw new Error(`Non-directory path (not ending with "/") "${filePath}" is and should not be a directory`)
71
+ }
72
+
73
+ return fs.readFileSync(filePath, 'utf-8');
74
+ }
75
+
76
+ export default function(element) {
77
+ return {
78
+ writeCssFile: writeCssFile.bind(element),
79
+ readSCSSFilesFromDirectory: readSCSSFilesFromDirectory.bind(element),
80
+ getCodeFromFile: getCodeFromFile.bind(element)
81
+ };
82
+ };