@wyw-in-js/turbopack-loader 1.0.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/types/index.js ADDED
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const shared_1 = require("@wyw-in-js/shared");
9
+ const transform_1 = require("@wyw-in-js/transform");
10
+ const css_modules_1 = require("./css-modules");
11
+ const file_utils_1 = require("./file-utils");
12
+ const insert_import_1 = require("./insert-import");
13
+ const DEFAULT_EXTENSION = '.wyw-in-js.module.css';
14
+ const stripQueryAndHash = (request) => {
15
+ const queryIdx = request.indexOf('?');
16
+ const hashIdx = request.indexOf('#');
17
+ if (queryIdx === -1) {
18
+ return hashIdx === -1 ? request : request.slice(0, hashIdx);
19
+ }
20
+ if (hashIdx === -1)
21
+ return request.slice(0, queryIdx);
22
+ return request.slice(0, Math.min(queryIdx, hashIdx));
23
+ };
24
+ const cache = new transform_1.TransformCacheCollection();
25
+ function convertSourceMap(value, filename) {
26
+ if (typeof value === 'string' || !value) {
27
+ return undefined;
28
+ }
29
+ return {
30
+ ...value,
31
+ file: value.file ?? filename,
32
+ mappings: value.mappings ?? '',
33
+ names: value.names ?? [],
34
+ sources: value.sources ?? [],
35
+ version: value.version ?? 3,
36
+ };
37
+ }
38
+ async function resolveWith(resolve, context, request) {
39
+ if (typeof resolve !== 'function')
40
+ return false;
41
+ if (resolve.length >= 3) {
42
+ return new Promise((ok, fail) => {
43
+ resolve(context, request, (err, result) => {
44
+ if (err)
45
+ fail(err);
46
+ else
47
+ ok(result ?? false);
48
+ });
49
+ });
50
+ }
51
+ return resolve(context, request);
52
+ }
53
+ const turbopackLoader = function turbopackLoader(content, inputSourceMap) {
54
+ const callbackFromAsync = typeof this.async === 'function' ? this.async() : undefined;
55
+ const callback = typeof callbackFromAsync === 'function' ? callbackFromAsync : this.callback;
56
+ if (typeof callback !== 'function') {
57
+ throw new Error('Async loader callback is not available');
58
+ }
59
+ (0, shared_1.logger)('turbopack-loader %s', this.resourcePath);
60
+ const { sourceMap, keepComments, prefixer, configFile, ...rest } = this.getOptions() || {};
61
+ if (configFile) {
62
+ const configPath = path_1.default.isAbsolute(configFile)
63
+ ? configFile
64
+ : path_1.default.join(process.cwd(), configFile);
65
+ this.addDependency(configPath);
66
+ }
67
+ const cssFileName = `${path_1.default.basename(this.resourcePath, path_1.default.extname(this.resourcePath))}${DEFAULT_EXTENSION}`;
68
+ const cssFilePath = path_1.default.join(path_1.default.dirname(this.resourcePath), cssFileName);
69
+ const cssImportPath = `./${cssFileName}`;
70
+ const resolveModule = this.getResolve({ dependencyType: 'esm' });
71
+ const asyncResolve = async (token, importer) => {
72
+ const context = path_1.default.isAbsolute(importer)
73
+ ? path_1.default.dirname(importer)
74
+ : path_1.default.join(process.cwd(), path_1.default.dirname(importer));
75
+ const result = await resolveWith(resolveModule, context, token);
76
+ if (!result) {
77
+ throw new Error(`Cannot resolve ${token} from ${context}`);
78
+ }
79
+ const filePath = stripQueryAndHash(result);
80
+ if (path_1.default.isAbsolute(filePath)) {
81
+ this.addDependency(filePath);
82
+ }
83
+ return result;
84
+ };
85
+ const transformServices = {
86
+ options: {
87
+ filename: this.resourcePath,
88
+ inputSourceMap: convertSourceMap(inputSourceMap, this.resourcePath),
89
+ pluginOptions: { configFile, ...rest },
90
+ prefixer,
91
+ keepComments,
92
+ root: process.cwd(),
93
+ },
94
+ cache,
95
+ emitWarning: (message) => {
96
+ if (typeof this.emitWarning === 'function') {
97
+ this.emitWarning(new Error(message));
98
+ }
99
+ },
100
+ };
101
+ (0, transform_1.transform)(transformServices, content.toString(), asyncResolve)
102
+ .then(async (result) => {
103
+ const rawCssText = result.cssText ?? '';
104
+ if (rawCssText.trim()) {
105
+ let cssText = (0, css_modules_1.makeCssModuleGlobal)(rawCssText);
106
+ if (sourceMap && typeof result.cssSourceMapText !== 'undefined') {
107
+ cssText += `\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from(result.cssSourceMapText).toString('base64')}*/\n`;
108
+ }
109
+ await Promise.all((result.dependencies ?? []).map((dep) => asyncResolve(dep, this.resourcePath)));
110
+ (0, file_utils_1.writeFileIfChanged)(cssFilePath, cssText);
111
+ const importStatement = `import ${JSON.stringify(cssImportPath)};`;
112
+ const finalCode = (0, insert_import_1.insertImportStatement)(result.code, importStatement);
113
+ callback(null, finalCode, result.sourceMap ?? undefined);
114
+ return;
115
+ }
116
+ if (fs_1.default.existsSync(cssFilePath)) {
117
+ (0, file_utils_1.writeFileIfChanged)(cssFilePath, '');
118
+ }
119
+ callback(null, result.code, result.sourceMap ?? undefined);
120
+ })
121
+ .catch((err) => callback(err));
122
+ };
123
+ exports.default = turbopackLoader;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Insert an import statement in a safe position:
3
+ * - after the last existing import declaration,
4
+ * - otherwise after the directive prologue (e.g. 'use client'),
5
+ * - otherwise at the top of the file.
6
+ */
7
+ export declare function insertImportStatement(code: string, importStatement: string): string;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.insertImportStatement = insertImportStatement;
4
+ /**
5
+ * Insert an import statement in a safe position:
6
+ * - after the last existing import declaration,
7
+ * - otherwise after the directive prologue (e.g. 'use client'),
8
+ * - otherwise at the top of the file.
9
+ */
10
+ function insertImportStatement(code, importStatement) {
11
+ if (code.includes(importStatement)) {
12
+ return code;
13
+ }
14
+ const importRegex = /^\s*(?:import\s+[^;]+?\s+from\s+["'][^"']+["'];|import\s*["'][^"']+["'];)/gm;
15
+ const importMatches = [...code.matchAll(importRegex)];
16
+ if (importMatches.length > 0) {
17
+ const lastImport = importMatches[importMatches.length - 1];
18
+ const insertPosition = lastImport.index + lastImport[0].length;
19
+ return `${code.slice(0, insertPosition)}\n${importStatement}${code.slice(insertPosition)}`;
20
+ }
21
+ const directiveRegex = /^(?:(?:\s*["']use \w+["'];?\s*\n?)+)/;
22
+ const directiveMatch = code.match(directiveRegex);
23
+ if (directiveMatch) {
24
+ const endOfDirectives = directiveMatch[0].length;
25
+ const needsNewline = !code.slice(0, endOfDirectives).endsWith('\n');
26
+ const separator = needsNewline ? '\n' : '';
27
+ return `${code.slice(0, endOfDirectives)}${separator}${importStatement}\n${code.slice(endOfDirectives)}`;
28
+ }
29
+ return `${importStatement}\n${code}`;
30
+ }