@e-mc/document 0.14.0 → 0.14.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 (3) hide show
  1. package/README.md +13 -12
  2. package/index.js +151 -5
  3. package/package.json +4 -7
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## Interface
11
11
 
12
- * [View Source](https://www.unpkg.com/@e-mc/types@0.14.0/lib/index.d.ts)
12
+ * [View Source](https://www.unpkg.com/@e-mc/types@0.14.1/lib/index.d.ts)
13
13
 
14
14
  ```typescript
15
15
  import type { DataSource, ViewEngine } from "./squared";
@@ -39,6 +39,7 @@ interface IDocument extends IClient<IFileManager, DocumentModule, TransformCallb
39
39
  resolveDir(name: string, ...paths: string[]): string | undefined;
40
40
  locateSourceFiles(file: ExternalAsset, code?: string, bundleContent?: string[]): ((imports?: ImportModule) => SourceInput | undefined);
41
41
  resolveSourceFile(file: ExternalAsset): ((code?: string, imports?: ImportModule) => SourceInput<string> | undefined);
42
+ resolvePackageJSONExports(uri: string, base?: string | URL): string | undefined;
42
43
  tryParse(source: string, format: string, options?: Record<string | number | symbol, unknown>): unknown;
43
44
  forDb(item: DataSource): boolean;
44
45
  hasEval(name: string): boolean;
@@ -92,7 +93,7 @@ interface DocumentConstructor extends ModuleConstructor {
92
93
 
93
94
  ```typescript
94
95
  import type { PermittedDirectories } from "./core";
95
- import type { DbModule, DbSettings, DocumentComponentOptions, PurgeComponent } from "./settings";
96
+ import type { DbModule, DbSettings, DocumentComponentOptions, ImportModule, PurgeComponent } from "./settings";
96
97
 
97
98
  interface DocumentModule {
98
99
  // handler: "@pi-r/chrome";
@@ -111,12 +112,12 @@ interface DocumentModule {
111
112
  filename?: string;
112
113
  };
113
114
  };
114
- imports?: StringMap;
115
+ imports?: ImportModule;
115
116
  settings?: {
116
117
  broadcast_id?: string | string[];
117
118
  users?: Record<string, {
118
119
  extensions?: string[] | null;
119
- imports?: StringMap;
120
+ imports?: ImportModule;
120
121
  imports_strict?: boolean;
121
122
  pages?: unknown;
122
123
  transform?: unknown;
@@ -187,14 +188,14 @@ NOTE: **@e-mc/document** is an abstract base class and cannot be instantiated. *
187
188
 
188
189
  ## References
189
190
 
190
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/squared.d.ts
191
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/asset.d.ts
192
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/core.d.ts
193
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/document.d.ts
194
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/filemanager.d.ts
195
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/logger.d.ts
196
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/settings.d.ts
197
- - https://www.unpkg.com/@e-mc/types@0.14.0/lib/watch.d.ts
191
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/squared.d.ts
192
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/asset.d.ts
193
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/core.d.ts
194
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/document.d.ts
195
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/filemanager.d.ts
196
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/logger.d.ts
197
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/settings.d.ts
198
+ - https://www.unpkg.com/@e-mc/types@0.14.1/lib/watch.d.ts
198
199
 
199
200
  ## LICENSE
200
201
 
package/index.js CHANGED
@@ -2,17 +2,22 @@
2
2
 
3
3
  const path = require('node:path');
4
4
  const fs = require('node:fs');
5
+ const mod = require('node:module');
5
6
  const pm = require('picomatch');
6
7
  const chalk = require('chalk');
8
+ const { pathToFileURL } = require('node:url');
7
9
  const { toUSVString } = require('node:util');
8
10
  const { load } = require('js-yaml');
9
- const { IMPORT_MAP, asExt, asFunction, cloneObject, coerceObject, createAbortError, errorMessage, errorValue, escapePattern, formatSize, getEncoding, hasGlob, hashKey, importESM, incrementUUID, isArray, isEmpty, isError, isFunction, isObject, isPlainObject, isString, parseExpires, requireESM } = require('@e-mc/types');
11
+ const { IMPORT_MAP, asExt, asFunction, cloneObject, coerceObject, createAbortError, errorMessage, errorValue, escapePattern, formatSize, getEncoding, hasGlob, hashKey, importESM, incrementUUID, isArray, isEmpty, isError, isFunction, isObject, isPlainObject, isString, manageGlobalObject, parseExpires, requireESM, supported } = require('@e-mc/types');
10
12
  const { Client } = require('@e-mc/core');
11
13
  const Db = require('@e-mc/db');
12
14
  const { SourceMap, TransformSeries } = require('@e-mc/document/transform');
13
15
  const { XmlWriter } = require('@e-mc/document/parse');
14
16
  const { PATTERN_PARENTHESIS, appendSuffix, concatString, getHashData, getIndent, getModuleName, getNewline, spliceString } = require('@e-mc/document/util');
15
17
  const kDocument = Symbol.for('document:constructor');
18
+ const SUPPORTED_GLOB = supported(22);
19
+ const SUPPORTED_PACKAGEJSON = supported(23, 2) || supported(22, 14, true);
20
+ const REGEXP_PACKAGEURI = /^(?:npm:)?((?:@[a-z\d-*~][a-z\d-*._~]*\/)?[a-z\d-~][a-z\d-._~]*\/.+)$/;
16
21
  const CACHE_PACKAGE = new Map();
17
22
  const CACHE_CONFIG = new Map();
18
23
  const CACHE_TEMPLATE = new Map();
@@ -27,8 +32,8 @@ function initCache() {
27
32
  CACHE_ETAG = Object.create(null);
28
33
  CACHE_CODE = Object.create(null);
29
34
  CACHE_HASH = Object.create(null);
30
- CACHE_PICOMATCH = Object.create(null);
31
35
  CACHE_EXTERNAL = Object.create(null);
36
+ CACHE_PICOMATCH = Object.create(null);
32
37
  }
33
38
  function deleteTransform(map, key, timeout) {
34
39
  if (timeout) {
@@ -50,12 +55,17 @@ function normalizeDir(value, check) {
50
55
  }
51
56
  return value.at(-1) === sep ? value : value + sep;
52
57
  }
58
+ function joinSpecifier(baseDir, specifier) {
59
+ const result = path.join(baseDir, specifier);
60
+ return Client.PLATFORM_WIN32 ? result.toLowerCase() : result;
61
+ }
53
62
  function cloneConfigItems(items) {
54
63
  const [a, b, c] = items;
55
64
  return [a, (typeof b === 'object' ? cloneObject(b, true) : b), typeof c === 'object' ? cloneObject(c, true) : c];
56
65
  }
57
66
  const isExcluded = (type, name, config, cacheData) => !(config?.hasType(type, name) || cacheData?.override === true);
58
67
  const wrapCount = (value) => chalk.grey('(') + value + chalk.grey(')');
68
+ const validateExports = (value) => typeof value === 'string' && value.startsWith('./') && !/\/\.{1,2}\//.test(value);
59
69
  const fixHint = (warningCount, errorCount, value) => warningCount > 0 || errorCount > 0 ? ':' + value : '';
60
70
  const compareValue = (value) => value.replace(/["'()]/g, '').trim();
61
71
  const toPath = (uri, hostname) => path.resolve(hostname[1], uri.slice(normalizeDir(hostname[0]).length).split('?')[0]);
@@ -635,6 +645,7 @@ class Document extends Client {
635
645
  _transformConfig = null;
636
646
  _mimeMap = null;
637
647
  _imports = null;
648
+ _packageJSON = { exports: false };
638
649
  constructor(data) {
639
650
  super(data);
640
651
  const transform = this.settingsOf('transform', 'cache');
@@ -648,8 +659,23 @@ class Document extends Client {
648
659
  if (config) {
649
660
  ({ baseUrl, ignoreModules, ignoreExtensions } = config);
650
661
  const users = this.getUserSettings();
651
- if (Array.isArray(users?.extensions)) {
652
- this._extensions = users.extensions.slice(0);
662
+ let package_json = this.settings.package_json;
663
+ if (users) {
664
+ if (Array.isArray(users.extensions)) {
665
+ this._extensions = users.extensions.slice(0);
666
+ }
667
+ if (users.package_json) {
668
+ package_json = users.package_json;
669
+ }
670
+ }
671
+ let jsonExports = package_json?.exports;
672
+ if (jsonExports) {
673
+ if (typeof jsonExports !== 'string') {
674
+ this._packageJSON.exports = true;
675
+ }
676
+ else if (Client.isDir(jsonExports = path.resolve(jsonExports))) {
677
+ this._packageJSON.exports = jsonExports;
678
+ }
653
679
  }
654
680
  if (baseUrl) {
655
681
  let pages = this.settings.pages;
@@ -940,7 +966,7 @@ class Document extends Client {
940
966
  if (!isPlainObject(imports)) {
941
967
  return;
942
968
  }
943
- const importsStrict = this.getUserSettings()?.imports_strict ?? this.settings.imports_strict;
969
+ const importsStrict = this.isImportsStrict();
944
970
  const scopes = (importsStrict ? this.findSourceScope(uri, imports) : []).concat([isPlainObject(imports.imports) ? imports.imports : imports]);
945
971
  const integrity = isPlainObject(imports.integrity) ? imports.integrity : undefined;
946
972
  const protocol = Client.isURL(uri);
@@ -1006,6 +1032,9 @@ class Document extends Client {
1006
1032
  return toPosix(result);
1007
1033
  }
1008
1034
  }
1035
+ if (!protocol && this._packageJSON.exports) {
1036
+ return this.resolvePackageJSONExports(uri);
1037
+ }
1009
1038
  }
1010
1039
  locateSourceFiles(file, code, bundleContent) {
1011
1040
  return (imports = this.imports) => {
@@ -1078,6 +1107,116 @@ class Document extends Client {
1078
1107
  }
1079
1108
  };
1080
1109
  }
1110
+ resolvePackageJSONExports(uri, base) {
1111
+ if (uri.startsWith('./')) {
1112
+ const cwd = [base && (base = Client.resolveFile(base)) && path.resolve(base) || this.host?.baseDirectory];
1113
+ if (SUPPORTED_PACKAGEJSON && cwd[0]) {
1114
+ try {
1115
+ const pathname = mod.findPackageJSON(pathToFileURL(cwd[0]));
1116
+ if (pathname) {
1117
+ cwd[0] = pathname;
1118
+ }
1119
+ }
1120
+ catch {
1121
+ }
1122
+ }
1123
+ if (!base) {
1124
+ cwd.push(process.cwd());
1125
+ }
1126
+ for (let i = 0; i < cwd.length; ++i) {
1127
+ const baseDir = cwd[i];
1128
+ if (baseDir) {
1129
+ try {
1130
+ const pathname = path.join(baseDir, 'package.json');
1131
+ if (fs.existsSync(pathname)) {
1132
+ const packageJSON = (i === 0 ? JSON.parse(fs.readFileSync(pathname, 'utf8')) : require(pathname));
1133
+ if (isPlainObject(packageJSON?.exports)) {
1134
+ const packageExports = packageJSON.exports;
1135
+ let value = packageExports[uri];
1136
+ if (value === null) {
1137
+ return;
1138
+ }
1139
+ if (validateExports(value) && Client.isFile(value = path.join(baseDir, value))) {
1140
+ return value;
1141
+ }
1142
+ const subDir = [];
1143
+ const globDir = [];
1144
+ for (const specifier in packageExports) {
1145
+ const target = packageExports[specifier];
1146
+ let items;
1147
+ if (validateExports(target)) {
1148
+ items = [target];
1149
+ }
1150
+ else if (isArray(items)) {
1151
+ items = items.filter(item => validateExports(item));
1152
+ }
1153
+ if (isArray(items) && validateExports(specifier)) {
1154
+ if (specifier.at(-1) === '/') {
1155
+ subDir.push([specifier, items]);
1156
+ }
1157
+ else if (SUPPORTED_GLOB && specifier.endsWith('/*')) {
1158
+ globDir.push([specifier.slice(0, -1), items.map(item => item.replaceAll('/*/', '/**/'))]);
1159
+ }
1160
+ }
1161
+ }
1162
+ uri = joinSpecifier(baseDir, uri);
1163
+ for (let [specifier, items] of subDir.sort((a, b) => b.length - a.length)) {
1164
+ if (uri.startsWith(specifier = joinSpecifier(baseDir, specifier))) {
1165
+ for (const target of items) {
1166
+ const result = path.join(baseDir, target, uri.slice(specifier.length));
1167
+ if (Client.isFile(result)) {
1168
+ return result;
1169
+ }
1170
+ if (this.isImportsStrict()) {
1171
+ break;
1172
+ }
1173
+ }
1174
+ }
1175
+ }
1176
+ for (let [specifier, items] of globDir.sort((a, b) => b.length - a.length)) {
1177
+ if (uri.startsWith(specifier = joinSpecifier(baseDir, specifier))) {
1178
+ for (const target of items) {
1179
+ try {
1180
+ const files = fs.globSync(target);
1181
+ if (files.length > 0) {
1182
+ const filename = uri.slice(specifier.length - 1);
1183
+ const result = files.filter(entry => entry.endsWith(filename) && Client.isFile(entry)).sort((a, b) => a.length - b.length).at(0);
1184
+ if (result) {
1185
+ return result;
1186
+ }
1187
+ }
1188
+ else if (this.isImportsStrict()) {
1189
+ break;
1190
+ }
1191
+ }
1192
+ catch {
1193
+ }
1194
+ }
1195
+ }
1196
+ }
1197
+ }
1198
+ }
1199
+ }
1200
+ catch {
1201
+ }
1202
+ }
1203
+ }
1204
+ }
1205
+ else if (!uri.startsWith('..') && !path.isAbsolute(uri)) {
1206
+ let baseUrl = this._packageJSON.exports;
1207
+ if (typeof baseUrl === 'string' && Client.isFile(baseUrl = path.join(baseUrl, uri))) {
1208
+ return baseUrl;
1209
+ }
1210
+ const match = REGEXP_PACKAGEURI.exec(uri);
1211
+ if (match) {
1212
+ try {
1213
+ return require.resolve(match[1]);
1214
+ }
1215
+ catch {
1216
+ }
1217
+ }
1218
+ }
1219
+ }
1081
1220
  tryParse(source, format, options) {
1082
1221
  try {
1083
1222
  switch (format.toLowerCase()) {
@@ -1493,6 +1632,9 @@ class Document extends Client {
1493
1632
  }
1494
1633
  return output;
1495
1634
  }
1635
+ isImportsStrict() {
1636
+ return !!(this.getUserSettings()?.imports_strict ?? this.settings.imports_strict);
1637
+ }
1496
1638
  #checkIntegrity(metadata, url, localUri) {
1497
1639
  const integrity = metadata?.[url];
1498
1640
  if (!isString(integrity)) {
@@ -1570,5 +1712,9 @@ class Document extends Client {
1570
1712
  }
1571
1713
  }
1572
1714
  initCache();
1715
+ manageGlobalObject(CACHE_PACKAGE);
1716
+ manageGlobalObject(CACHE_VIEWENGINE);
1717
+ manageGlobalObject(CACHE_EXTERNAL);
1718
+ manageGlobalObject(CACHE_PICOMATCH);
1573
1719
 
1574
1720
  module.exports = Document;
package/package.json CHANGED
@@ -1,12 +1,9 @@
1
1
  {
2
2
  "name": "@e-mc/document",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "Document constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
- "publishConfig": {
8
- "access": "public"
9
- },
10
7
  "repository": {
11
8
  "type": "git",
12
9
  "url": "git+https://github.com/anpham6/e-mc.git",
@@ -19,9 +16,9 @@
19
16
  "license": "BSD-3-Clause",
20
17
  "homepage": "https://github.com/anpham6/e-mc#readme",
21
18
  "dependencies": {
22
- "@e-mc/core": "0.14.0",
23
- "@e-mc/db": "0.14.0",
24
- "@e-mc/types": "0.14.0",
19
+ "@e-mc/core": "0.14.1",
20
+ "@e-mc/db": "0.14.1",
21
+ "@e-mc/types": "0.14.1",
25
22
  "chalk": "4.1.2",
26
23
  "domhandler": "^5.0.3",
27
24
  "domutils": "^3.2.2",