tshtml-loader 1.3.0 → 1.4.3
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/dist/export-template.d.ts +3 -0
- package/dist/export-template.js +78 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +250 -0
- package/package.json +56 -28
- package/lib/export-template.d.ts +0 -2
- package/lib/export-template.js +0 -42
- package/lib/index.d.ts +0 -7
- package/lib/index.js +0 -195
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
/**
|
|
38
|
+
* CLI helper to compile a single .tshtml file to .html on disk.
|
|
39
|
+
*/
|
|
40
|
+
const fs_1 = require("fs");
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const index_1 = require("./index");
|
|
43
|
+
// ----------------------------------------------------------------------------------
|
|
44
|
+
if (process.argv.length !== 3) {
|
|
45
|
+
console.error("Please specify one .tshtml file");
|
|
46
|
+
process.exit();
|
|
47
|
+
}
|
|
48
|
+
const fileName = process.argv[2];
|
|
49
|
+
const extension = path.extname(fileName).toLowerCase();
|
|
50
|
+
if (extension !== ".tshtml") {
|
|
51
|
+
console.error("Input file must have .tshtml extension");
|
|
52
|
+
process.exit();
|
|
53
|
+
}
|
|
54
|
+
const fileNameNoExtension = fileName.substr(0, fileName.length - extension.length);
|
|
55
|
+
const outputFileName = fileNameNoExtension + ".html";
|
|
56
|
+
(0, fs_1.readFile)(fileName, { encoding: 'utf-8' }, function (err, data) {
|
|
57
|
+
if (!err) {
|
|
58
|
+
// Transform the source
|
|
59
|
+
const result = (0, index_1.executeTemplate)(data, path.join(process.cwd(), "/test.html"));
|
|
60
|
+
const htmlResult = (0, index_1.templateToString)(result.exports.default);
|
|
61
|
+
// Write to destination
|
|
62
|
+
// process.stdout.write( htmlResult );
|
|
63
|
+
(0, fs_1.writeFile)(outputFileName, htmlResult, {
|
|
64
|
+
encoding: "utf8",
|
|
65
|
+
flag: "w",
|
|
66
|
+
}, writeErr => {
|
|
67
|
+
if (!writeErr) {
|
|
68
|
+
console.log(`File is written: ${outputFileName}`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.log(`Error writing to the output file ${outputFileName}`, writeErr);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(`Error reading the input file ${fileName}`, err);
|
|
77
|
+
}
|
|
78
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as webpack from "webpack";
|
|
2
|
+
/**
|
|
3
|
+
* Webpack loader entry point for .tshtml files. Executes the template code and
|
|
4
|
+
* returns compiled HTML while registering file dependencies with webpack.
|
|
5
|
+
* @param this Loader context provided by webpack
|
|
6
|
+
* @param source Raw .tshtml source code
|
|
7
|
+
*/
|
|
8
|
+
export default function (this: webpack.LoaderContext<any>, source: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Compile and execute a .tshtml template in an isolated VM context while
|
|
11
|
+
* tracking all file dependencies loaded via require().
|
|
12
|
+
* @param code Template source
|
|
13
|
+
* @param fileName Absolute path of the template file (used for resolution)
|
|
14
|
+
*/
|
|
15
|
+
export declare function executeTemplate(code: string, fileName: string): {
|
|
16
|
+
exports: any;
|
|
17
|
+
dependencies: string[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Convert different template builder outputs into a final HTML string.
|
|
21
|
+
* Accepts strings, class constructors (invoked), tshtml tags/arrays, or objects with toString().
|
|
22
|
+
*/
|
|
23
|
+
export declare function templateToString(builder: any): string;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.default = default_1;
|
|
37
|
+
exports.executeTemplate = executeTemplate;
|
|
38
|
+
exports.templateToString = templateToString;
|
|
39
|
+
const lodash_1 = require("lodash");
|
|
40
|
+
const ts_node_1 = require("ts-node");
|
|
41
|
+
const fs_1 = require("fs");
|
|
42
|
+
const path_1 = require("path");
|
|
43
|
+
const vm_1 = require("vm");
|
|
44
|
+
const webpack = __importStar(require("webpack"));
|
|
45
|
+
const tshtml_1 = require("tshtml");
|
|
46
|
+
const Module = require("module");
|
|
47
|
+
// ----------------------------------------------------------------------------------
|
|
48
|
+
// tshtml-loader implementation
|
|
49
|
+
/**
|
|
50
|
+
* Webpack loader entry point for .tshtml files. Executes the template code and
|
|
51
|
+
* returns compiled HTML while registering file dependencies with webpack.
|
|
52
|
+
* @param this Loader context provided by webpack
|
|
53
|
+
* @param source Raw .tshtml source code
|
|
54
|
+
*/
|
|
55
|
+
function default_1(source) {
|
|
56
|
+
let result;
|
|
57
|
+
let htmlResult;
|
|
58
|
+
let builder;
|
|
59
|
+
try {
|
|
60
|
+
result = executeTemplate(source, this.resourcePath);
|
|
61
|
+
builder = result.exports.default;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new Error(`Error executing template: ${error.message}\n ${error.stack}`);
|
|
65
|
+
}
|
|
66
|
+
if (builder == null) {
|
|
67
|
+
throw new Error(`Template must be exported as "default".`);
|
|
68
|
+
}
|
|
69
|
+
htmlResult = templateToString(builder);
|
|
70
|
+
// Dependencies
|
|
71
|
+
const reTestNodeFolder = /[\/\\]node_modules[\/\\]/;
|
|
72
|
+
const filteredDependencies = (0, lodash_1.filter)(result.dependencies, x => x.startsWith(this.rootContext) && !reTestNodeFolder.test(x));
|
|
73
|
+
for (let file of filteredDependencies) {
|
|
74
|
+
this.addDependency(file);
|
|
75
|
+
}
|
|
76
|
+
// In case of AOT build add the resulting HTML to the assets
|
|
77
|
+
if (this._compilation.name === "angular-compiler:resource") {
|
|
78
|
+
const compilation = this._compilation;
|
|
79
|
+
const rawRequest = this._module.rawRequest;
|
|
80
|
+
const request = rawRequest.substring(0, rawRequest.lastIndexOf("?"));
|
|
81
|
+
// postpone to a later event, because when loader is invoked, the chunks don't yet exist, and we need to register the file
|
|
82
|
+
compilation.hooks.processAssets.tap({
|
|
83
|
+
name: "tshtml-loader",
|
|
84
|
+
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS
|
|
85
|
+
}, (assets) => {
|
|
86
|
+
compilation.emitAsset(request, new webpack.sources.RawSource(htmlResult));
|
|
87
|
+
compilation.addChunk("resource").files.add(request);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return htmlResult;
|
|
91
|
+
}
|
|
92
|
+
// ----------------------------------------------------------------------------------
|
|
93
|
+
//
|
|
94
|
+
/**
|
|
95
|
+
* Compile and execute a .tshtml template in an isolated VM context while
|
|
96
|
+
* tracking all file dependencies loaded via require().
|
|
97
|
+
* @param code Template source
|
|
98
|
+
* @param fileName Absolute path of the template file (used for resolution)
|
|
99
|
+
*/
|
|
100
|
+
function executeTemplate(code, fileName) {
|
|
101
|
+
const dirName = (0, path_1.dirname)(fileName);
|
|
102
|
+
const output = compileCode(code, fileName);
|
|
103
|
+
const script = new vm_1.Script(output, { filename: fileName });
|
|
104
|
+
const module = new Module(fileName);
|
|
105
|
+
module.filename = fileName;
|
|
106
|
+
module.loaded = true;
|
|
107
|
+
module.paths = Module._nodeModulePaths(dirName);
|
|
108
|
+
const req = createRequireService(fileName);
|
|
109
|
+
const sandbox = {
|
|
110
|
+
__filename: fileName,
|
|
111
|
+
__dirname: dirName,
|
|
112
|
+
module: module,
|
|
113
|
+
exports: module.exports,
|
|
114
|
+
require: req,
|
|
115
|
+
};
|
|
116
|
+
script.runInNewContext(sandbox, {
|
|
117
|
+
filename: fileName,
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
exports: sandbox.exports,
|
|
121
|
+
dependencies: req.dependencies,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert different template builder outputs into a final HTML string.
|
|
126
|
+
* Accepts strings, class constructors (invoked), tshtml tags/arrays, or objects with toString().
|
|
127
|
+
*/
|
|
128
|
+
function templateToString(builder) {
|
|
129
|
+
if (builder == null) {
|
|
130
|
+
return "";
|
|
131
|
+
}
|
|
132
|
+
else if ((0, lodash_1.isString)(builder)) {
|
|
133
|
+
return builder;
|
|
134
|
+
}
|
|
135
|
+
else if (typeof (builder) == "function") {
|
|
136
|
+
return (new builder()).toString();
|
|
137
|
+
}
|
|
138
|
+
else if ((0, lodash_1.isArray)(builder) || (0, tshtml_1.isTag)(builder)) {
|
|
139
|
+
return (0, tshtml_1.tagToString)(builder);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
return builder.toString();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
let compilerService;
|
|
146
|
+
/***
|
|
147
|
+
* Compiles given TypeScript code
|
|
148
|
+
* @param code
|
|
149
|
+
* @param fileName
|
|
150
|
+
*/
|
|
151
|
+
/**
|
|
152
|
+
* Compile TypeScript source using ts-node with Node16 settings.
|
|
153
|
+
* @param code Source code
|
|
154
|
+
* @param fileName File name used for source maps and module resolution
|
|
155
|
+
*/
|
|
156
|
+
function compileCode(code, fileName) {
|
|
157
|
+
const tsFileName = `${fileName}.ts`;
|
|
158
|
+
if (compilerService == null) {
|
|
159
|
+
compilerService = (0, ts_node_1.register)({
|
|
160
|
+
compilerOptions: {
|
|
161
|
+
module: "Node16",
|
|
162
|
+
target: "es2022",
|
|
163
|
+
moduleResolution: "node16",
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return compilerService.compile(code, tsFileName);
|
|
168
|
+
}
|
|
169
|
+
/***
|
|
170
|
+
* Create a logging wrapper for "require" function.
|
|
171
|
+
* @param fileName
|
|
172
|
+
*/
|
|
173
|
+
/**
|
|
174
|
+
* Wrap Node's require to track dependency files and evict stale modules when underlying files change.
|
|
175
|
+
* @param fileName The template file being executed
|
|
176
|
+
*/
|
|
177
|
+
function createRequireService(fileName) {
|
|
178
|
+
const req = Module.createRequire(fileName);
|
|
179
|
+
const cache = req.cache;
|
|
180
|
+
const dependencies = [];
|
|
181
|
+
const resolveFn = (id, options) => {
|
|
182
|
+
return req.resolve(id, options);
|
|
183
|
+
};
|
|
184
|
+
resolveFn.paths = req.resolve.paths;
|
|
185
|
+
const requireFn = (request) => {
|
|
186
|
+
let filePath;
|
|
187
|
+
try {
|
|
188
|
+
filePath = resolveFn(request);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
// Likely file doesn't exist, so short circuit to the default implementation
|
|
192
|
+
return req(request);
|
|
193
|
+
}
|
|
194
|
+
// Try to get the module from cache and check it's modification time
|
|
195
|
+
let module = cache[filePath];
|
|
196
|
+
if (module != null) {
|
|
197
|
+
cleanOutdatedModules(module, {});
|
|
198
|
+
}
|
|
199
|
+
const result = req(request);
|
|
200
|
+
// Store last modification date
|
|
201
|
+
const allFiles = {};
|
|
202
|
+
storeModuleTimes(cache[filePath], allFiles);
|
|
203
|
+
// Store request to the dependency resolution log
|
|
204
|
+
dependencies.push(...(0, lodash_1.keys)(allFiles));
|
|
205
|
+
return result;
|
|
206
|
+
};
|
|
207
|
+
requireFn.resolve = resolveFn;
|
|
208
|
+
requireFn.cache = cache;
|
|
209
|
+
requireFn.extensions = req.extensions;
|
|
210
|
+
requireFn.main = req.main;
|
|
211
|
+
requireFn.dependencies = dependencies;
|
|
212
|
+
return requireFn;
|
|
213
|
+
// ---
|
|
214
|
+
function cleanOutdatedModules(module, allFiles) {
|
|
215
|
+
allFiles[module.filename] = true;
|
|
216
|
+
let doClean = false;
|
|
217
|
+
// If the module file was modified since last access -> remove it from the cache
|
|
218
|
+
if (module.fileLastModified != null) {
|
|
219
|
+
const moduleTime = (0, fs_1.statSync)(module.filename).mtimeMs;
|
|
220
|
+
if (module.fileLastModified != moduleTime) {
|
|
221
|
+
doClean = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Check if any child module is outdated
|
|
225
|
+
for (let childModule of module.children) {
|
|
226
|
+
if (allFiles[childModule.filename] || !checkFilename(childModule.filename))
|
|
227
|
+
continue;
|
|
228
|
+
doClean = cleanOutdatedModules(childModule, allFiles) || doClean;
|
|
229
|
+
}
|
|
230
|
+
if (doClean) {
|
|
231
|
+
delete cache[module.filename];
|
|
232
|
+
}
|
|
233
|
+
return doClean;
|
|
234
|
+
}
|
|
235
|
+
function storeModuleTimes(module, allFiles) {
|
|
236
|
+
allFiles[module.filename] = true;
|
|
237
|
+
if (module.fileLastModified == null) {
|
|
238
|
+
module.fileLastModified = (0, fs_1.statSync)(module.filename).mtimeMs;
|
|
239
|
+
}
|
|
240
|
+
let childModule;
|
|
241
|
+
for (childModule of module.children) {
|
|
242
|
+
if (allFiles[childModule.filename] || !checkFilename(childModule.filename))
|
|
243
|
+
continue;
|
|
244
|
+
storeModuleTimes(childModule, allFiles);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function checkFilename(filename) {
|
|
248
|
+
return filename.indexOf("\\node_modules\\") === -1;
|
|
249
|
+
}
|
|
250
|
+
}
|
package/package.json
CHANGED
|
@@ -1,28 +1,56 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "tshtml-loader",
|
|
3
|
-
"version": "1.3
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
}
|
|
28
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "tshtml-loader",
|
|
3
|
+
"version": "1.4.3",
|
|
4
|
+
"description": "Webpack loader for tshtml template files",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/xorets/tshtml"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/**/*.js",
|
|
13
|
+
"dist/**/*.d.ts"
|
|
14
|
+
],
|
|
15
|
+
"bin": "./dist/export-template.js",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"require": "./dist/index.js",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"registry": "https://registry.npmjs.org/",
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc --project . --outDir ./dist --module commonjs --declaration --declarationMap --skipLibCheck true",
|
|
30
|
+
"build-watch": "tsc --project . --outDir ./dist -d -w",
|
|
31
|
+
"pretest": "cd ../tshtml && npm run build --if-present",
|
|
32
|
+
"test": "tsx ./test/jasmine.js",
|
|
33
|
+
"coverage": "nyc tsx ./test/jasmine.js",
|
|
34
|
+
"prepublishOnly": "npm run test && npm run build"
|
|
35
|
+
},
|
|
36
|
+
"author": "LOGEX Group",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/jasmine": "^5.1.15",
|
|
40
|
+
"@types/lodash": "4.17.23",
|
|
41
|
+
"@types/node": "25.0.9",
|
|
42
|
+
"@types/webpack": "5.28.5",
|
|
43
|
+
"jasmine": "6.0.0",
|
|
44
|
+
"nyc": "^17.1.0",
|
|
45
|
+
"tsx": "^4.21.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"lodash": "^4.17.21",
|
|
49
|
+
"ts-node": "^10.9.2",
|
|
50
|
+
"tshtml": "^1.4.3",
|
|
51
|
+
"typescript": "^5.9.3"
|
|
52
|
+
},
|
|
53
|
+
"overrides": {
|
|
54
|
+
"diff": "^8.0.3"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/lib/export-template.d.ts
DELETED
package/lib/export-template.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
var fs_1 = require("fs");
|
|
5
|
-
var path = require("node:path");
|
|
6
|
-
var index_1 = require("./index");
|
|
7
|
-
// ----------------------------------------------------------------------------------
|
|
8
|
-
if (process.argv.length !== 3) {
|
|
9
|
-
console.error("Please specify one .tshtml file");
|
|
10
|
-
process.exit();
|
|
11
|
-
}
|
|
12
|
-
var fileName = process.argv[2];
|
|
13
|
-
var extension = path.extname(fileName).toLowerCase();
|
|
14
|
-
if (extension !== ".tshtml") {
|
|
15
|
-
console.error("Input file must have .tshtml extension");
|
|
16
|
-
process.exit();
|
|
17
|
-
}
|
|
18
|
-
var fileNameNoExtension = fileName.substr(0, fileName.length - extension.length);
|
|
19
|
-
var outputFileName = fileNameNoExtension + ".html";
|
|
20
|
-
(0, fs_1.readFile)(fileName, { encoding: 'utf-8' }, function (err, data) {
|
|
21
|
-
if (!err) {
|
|
22
|
-
// Transform the source
|
|
23
|
-
var result = (0, index_1.executeTemplate)(data, path.join(process.cwd(), "/test.html"));
|
|
24
|
-
var htmlResult = (0, index_1.templateToString)(result.exports.default);
|
|
25
|
-
// Write to destination
|
|
26
|
-
// process.stdout.write( htmlResult );
|
|
27
|
-
(0, fs_1.writeFile)(outputFileName, htmlResult, {
|
|
28
|
-
encoding: "utf8",
|
|
29
|
-
flag: "w",
|
|
30
|
-
}, function (writeErr) {
|
|
31
|
-
if (!writeErr) {
|
|
32
|
-
console.log("File is written: ".concat(outputFileName));
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
console.log("Error writing to the output file ".concat(outputFileName), writeErr);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
console.log("Error reading the input file ".concat(fileName), err);
|
|
41
|
-
}
|
|
42
|
-
});
|
package/lib/index.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import * as webpack from "webpack";
|
|
2
|
-
export default function (this: webpack.LoaderContext<any>, source: string): string;
|
|
3
|
-
export declare function executeTemplate(code: string, fileName: string): {
|
|
4
|
-
exports: any;
|
|
5
|
-
dependencies: string[];
|
|
6
|
-
};
|
|
7
|
-
export declare function templateToString(builder: any): string;
|
package/lib/index.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = default_1;
|
|
4
|
-
exports.executeTemplate = executeTemplate;
|
|
5
|
-
exports.templateToString = templateToString;
|
|
6
|
-
var lodash_1 = require("lodash");
|
|
7
|
-
var ts_node_1 = require("ts-node");
|
|
8
|
-
var fs_1 = require("fs");
|
|
9
|
-
var path_1 = require("path");
|
|
10
|
-
var vm_1 = require("vm");
|
|
11
|
-
var webpack = require("webpack");
|
|
12
|
-
var tshtml_1 = require("tshtml");
|
|
13
|
-
require("tsconfig-paths/register"); // Necessary to support @folders resolution by Nodejs
|
|
14
|
-
var Module = require("module");
|
|
15
|
-
// ----------------------------------------------------------------------------------
|
|
16
|
-
// tshtml-loader implementation
|
|
17
|
-
function default_1(source) {
|
|
18
|
-
var _this = this;
|
|
19
|
-
var result;
|
|
20
|
-
var htmlResult;
|
|
21
|
-
var builder;
|
|
22
|
-
try {
|
|
23
|
-
result = executeTemplate(source, this.resourcePath);
|
|
24
|
-
builder = result.exports.default;
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
throw new Error("Error executing template: ".concat(error.message, "\n ").concat(error.stack));
|
|
28
|
-
}
|
|
29
|
-
if (builder == null) {
|
|
30
|
-
throw new Error("Template must be exported as \"default\".");
|
|
31
|
-
}
|
|
32
|
-
htmlResult = templateToString(builder);
|
|
33
|
-
// Dependencies
|
|
34
|
-
var reTestNodeFolder = /[\/\\]node_modules[\/\\]/;
|
|
35
|
-
var filteredDependencies = (0, lodash_1.filter)(result.dependencies, function (x) {
|
|
36
|
-
return x.startsWith(_this.rootContext) && !reTestNodeFolder.test(x);
|
|
37
|
-
});
|
|
38
|
-
for (var _i = 0, filteredDependencies_1 = filteredDependencies; _i < filteredDependencies_1.length; _i++) {
|
|
39
|
-
var file = filteredDependencies_1[_i];
|
|
40
|
-
this.addDependency(file);
|
|
41
|
-
}
|
|
42
|
-
// In case of AOT build add the resulting HTML to the assets
|
|
43
|
-
if (this._compilation.name === "angular-compiler:resource") {
|
|
44
|
-
var compilation_1 = this._compilation;
|
|
45
|
-
var rawRequest = this._module.rawRequest;
|
|
46
|
-
var request_1 = rawRequest.substring(0, rawRequest.lastIndexOf("?"));
|
|
47
|
-
// postpone to a later event, because when loader is invoked, the chunks don’t yet exist, and we need to register the file
|
|
48
|
-
compilation_1.hooks.processAssets.tap({
|
|
49
|
-
name: "tshtml-loader",
|
|
50
|
-
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS
|
|
51
|
-
}, function (assets) {
|
|
52
|
-
compilation_1.emitAsset(request_1, new webpack.sources.RawSource(htmlResult));
|
|
53
|
-
compilation_1.addChunk("resource").files.add(request_1);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
return htmlResult;
|
|
57
|
-
}
|
|
58
|
-
// ----------------------------------------------------------------------------------
|
|
59
|
-
//
|
|
60
|
-
function executeTemplate(code, fileName) {
|
|
61
|
-
var dirName = (0, path_1.dirname)(fileName);
|
|
62
|
-
var output = compileCode(code, fileName);
|
|
63
|
-
var script = new vm_1.Script(output, { filename: fileName });
|
|
64
|
-
var module = new Module(fileName);
|
|
65
|
-
module.filename = fileName;
|
|
66
|
-
module.loaded = true;
|
|
67
|
-
module.paths = Module._nodeModulePaths(dirName);
|
|
68
|
-
var req = createRequireService(fileName);
|
|
69
|
-
var sandbox = {
|
|
70
|
-
__filename: fileName,
|
|
71
|
-
__dirname: dirName,
|
|
72
|
-
module: module,
|
|
73
|
-
exports: module.exports,
|
|
74
|
-
require: req,
|
|
75
|
-
};
|
|
76
|
-
script.runInNewContext(sandbox, {
|
|
77
|
-
filename: fileName,
|
|
78
|
-
});
|
|
79
|
-
return {
|
|
80
|
-
exports: sandbox.exports,
|
|
81
|
-
dependencies: req.dependencies,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function templateToString(builder) {
|
|
85
|
-
if ((0, lodash_1.isString)(builder)) {
|
|
86
|
-
return builder;
|
|
87
|
-
}
|
|
88
|
-
else if (typeof (builder) == "function") {
|
|
89
|
-
return (new builder()).toString();
|
|
90
|
-
}
|
|
91
|
-
else if ((0, lodash_1.isArray)(builder) || (0, tshtml_1.isTag)(builder)) {
|
|
92
|
-
return (0, tshtml_1.tagToString)(builder);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
return builder.toString();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
var compilerService;
|
|
99
|
-
/***
|
|
100
|
-
* Compiles given TypeScript code
|
|
101
|
-
* @param code
|
|
102
|
-
* @param fileName
|
|
103
|
-
*/
|
|
104
|
-
function compileCode(code, fileName) {
|
|
105
|
-
var tsFileName = "".concat(fileName, ".ts");
|
|
106
|
-
if (compilerService == null) {
|
|
107
|
-
compilerService = (0, ts_node_1.register)({
|
|
108
|
-
compilerOptions: {
|
|
109
|
-
module: "CommonJS",
|
|
110
|
-
target: "es2015",
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
return compilerService.compile(code, tsFileName);
|
|
115
|
-
}
|
|
116
|
-
/***
|
|
117
|
-
* Create a logging wrapper for "require" function.
|
|
118
|
-
* @param fileName
|
|
119
|
-
*/
|
|
120
|
-
function createRequireService(fileName) {
|
|
121
|
-
var req = Module.createRequire(fileName);
|
|
122
|
-
var cache = req.cache;
|
|
123
|
-
var dependencies = [];
|
|
124
|
-
var resolveFn = function (id, options) {
|
|
125
|
-
return req.resolve(id, options);
|
|
126
|
-
};
|
|
127
|
-
resolveFn.paths = req.resolve.paths;
|
|
128
|
-
var requireFn = function (request) {
|
|
129
|
-
var filePath;
|
|
130
|
-
try {
|
|
131
|
-
filePath = resolveFn(request);
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
// Likely file doesn't exist, so short circuit to the default implementation
|
|
135
|
-
return req(request);
|
|
136
|
-
}
|
|
137
|
-
// Try to get the module from cache and check it's modification time
|
|
138
|
-
var module = cache[filePath];
|
|
139
|
-
if (module != null) {
|
|
140
|
-
cleanOutdatedModules(module, {});
|
|
141
|
-
}
|
|
142
|
-
var result = req(request);
|
|
143
|
-
// Store last modification date
|
|
144
|
-
var allFiles = {};
|
|
145
|
-
storeModuleTimes(cache[filePath], allFiles);
|
|
146
|
-
// Store request to the dependency resolution log
|
|
147
|
-
dependencies.push.apply(dependencies, (0, lodash_1.keys)(allFiles));
|
|
148
|
-
return result;
|
|
149
|
-
};
|
|
150
|
-
requireFn.resolve = resolveFn;
|
|
151
|
-
requireFn.cache = cache;
|
|
152
|
-
requireFn.extensions = req.extensions;
|
|
153
|
-
requireFn.main = req.main;
|
|
154
|
-
requireFn.dependencies = dependencies;
|
|
155
|
-
return requireFn;
|
|
156
|
-
// ---
|
|
157
|
-
function cleanOutdatedModules(module, allFiles) {
|
|
158
|
-
allFiles[module.filename] = true;
|
|
159
|
-
var doClean = false;
|
|
160
|
-
// If the module file was modified since last access -> remove it from the cache
|
|
161
|
-
if (module.fileLastModified != null) {
|
|
162
|
-
var moduleTime = (0, fs_1.statSync)(module.filename).mtimeMs;
|
|
163
|
-
if (module.fileLastModified != moduleTime) {
|
|
164
|
-
doClean = true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
// Check if any child module is outdated
|
|
168
|
-
for (var _i = 0, _a = module.children; _i < _a.length; _i++) {
|
|
169
|
-
var childModule = _a[_i];
|
|
170
|
-
if (allFiles[childModule.filename] || !checkFilename(childModule.filename))
|
|
171
|
-
continue;
|
|
172
|
-
doClean = cleanOutdatedModules(childModule, allFiles) || doClean;
|
|
173
|
-
}
|
|
174
|
-
if (doClean) {
|
|
175
|
-
delete cache[module.filename];
|
|
176
|
-
}
|
|
177
|
-
return doClean;
|
|
178
|
-
}
|
|
179
|
-
function storeModuleTimes(module, allFiles) {
|
|
180
|
-
allFiles[module.filename] = true;
|
|
181
|
-
if (module.fileLastModified == null) {
|
|
182
|
-
module.fileLastModified = (0, fs_1.statSync)(module.filename).mtimeMs;
|
|
183
|
-
}
|
|
184
|
-
var childModule;
|
|
185
|
-
for (var _i = 0, _a = module.children; _i < _a.length; _i++) {
|
|
186
|
-
childModule = _a[_i];
|
|
187
|
-
if (allFiles[childModule.filename] || !checkFilename(childModule.filename))
|
|
188
|
-
continue;
|
|
189
|
-
storeModuleTimes(childModule, allFiles);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
function checkFilename(filename) {
|
|
193
|
-
return filename.indexOf("\\node_modules\\") === -1;
|
|
194
|
-
}
|
|
195
|
-
}
|