tungsten 0.2.15 → 0.2.17

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.
@@ -74,5 +74,6 @@ export type FrameworkConfigCompleteWithoutRootComponent = FrameworkConfigComplet
74
74
  useRootComponent: false;
75
75
  };
76
76
  export type FrameworkConfigComplete = FrameworkConfigCompleteWithRootComponent | FrameworkConfigCompleteWithoutRootComponent;
77
+ export type FrameworkConfigOverrides = Pick<FrameworkConfigCompleteBase, 'ignoreDirs' | 'ignorePatterns'>;
77
78
  export {};
78
79
  //# sourceMappingURL=FrameworkConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FrameworkConfig.d.ts","sourceRoot":"","sources":["../src/FrameworkConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FrameworkConfig.d.ts","sourceRoot":"","sources":["../src/FrameworkConfig.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { Module } from '../CjsTypes.js';
1
2
  declare global {
2
3
  interface Window {
3
4
  __tungsten_cjs_import: (location: string) => Promise<{
@@ -5,5 +6,5 @@ declare global {
5
6
  }>;
6
7
  }
7
8
  }
8
- export {};
9
+ export declare function loadDeps(deps: string[]): Promise<Record<string, Module>>;
9
10
  //# sourceMappingURL=cjsHelpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cjsHelpers.d.ts","sourceRoot":"","sources":["../../src/_client/cjsHelpers.ts"],"names":[],"mappings":"AAmCA,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC,CAAA;KAC/E;CACJ"}
1
+ {"version":3,"file":"cjsHelpers.d.ts","sourceRoot":"","sources":["../../src/_client/cjsHelpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,gBAAgB,CAAA;AAkCvD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC,CAAA;KAC/E;CACJ;AA6BD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,mCAuC5C"}
@@ -40,19 +40,32 @@ function pathCombine(baseFile, dest) {
40
40
  throw new Error(`pathCombine error: unknown dest format, expected a relative import. baseDir: ${baseDir} dest: ${dest}`);
41
41
  }
42
42
  }
43
- async function loadDeps(deps) {
43
+ export async function loadDeps(deps) {
44
44
  const loaded = {};
45
45
  const proms = [];
46
- deps.forEach(async dep => {
47
- if (dep.endsWith('json')) {
48
- proms.push(fetch(dep).then(res => res.json()).then(json => loaded[dep] = json));
49
- } else {
50
- proms.push(import(dep).then(m => {
51
- loaded[dep] = m.default;
52
- proms.push(loadDeps(m.deps).then(mods => Object.assign(loaded, mods)));
53
- }));
46
+ // Every dep is queued at most once. Without this, a circular require() between two
47
+ // converted CJS files (common in packages split over many small files) queues the pair
48
+ // forever: the browser serves the repeat import() from its module cache, so nothing
49
+ // fails or even slows down - the returned promise simply never settles, and every
50
+ // import() waiting on that module graph hangs with it.
51
+ const queued = new Set();
52
+ function queueDeps(deps) {
53
+ if (deps === undefined) return;
54
+ for (const dep of deps) {
55
+ if (queued.has(dep)) continue;
56
+ queued.add(dep);
57
+ if (dep.endsWith('json')) {
58
+ proms.push(fetch(dep).then(res => res.json()).then(json => loaded[dep] = json));
59
+ } else {
60
+ proms.push(import(dep).then(m => {
61
+ loaded[dep] = m.default;
62
+ queueDeps(m.deps);
63
+ }));
64
+ }
54
65
  }
55
- });
66
+ }
67
+ queueDeps(deps);
68
+ // queueDeps() adds to proms as each module arrives with its own deps
56
69
  let resolved = 0;
57
70
  while (resolved < proms.length) {
58
71
  const results = await Promise.all(proms);
@@ -104,5 +117,4 @@ window.__tungsten_cjs_import = async function __tungsten_cjs_import(location /*
104
117
  cjsModule(module, module.exports, createRequire(location, loadedDeps, cjsModuleCache));
105
118
  return module.exports;
106
119
  };
107
- export {};
108
120
  //}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cjsHelpers.sxyt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cjsHelpers.sxyt.d.ts","sourceRoot":"","sources":["../../src/_client/cjsHelpers.sxyt.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import { expect } from 'chai';
2
+ import { describe } from 'sxy-test-runner';
3
+ import { mkdtemp, rm, writeFile } from 'fs/promises';
4
+ import { tmpdir } from 'os';
5
+ import { join } from 'path';
6
+ import { pathToFileURL } from 'url';
7
+ // cjsHelpers is browser code - it installs a `process` shim and a window global as soon as
8
+ // it is imported. Stub the window it expects and put node's own process back afterwards.
9
+ const nodeProcess = Reflect.get(globalThis, 'process');
10
+ Reflect.set(globalThis, 'window', {});
11
+ const {
12
+ loadDeps
13
+ } = await import("./cjsHelpers.js");
14
+ Reflect.set(globalThis, 'process', nodeProcess);
15
+ // a converted CJS module exports its factory as the default and its dependencies as `deps`
16
+ function moduleSource(deps) {
17
+ return `export const deps = ${JSON.stringify(deps)}\n` + 'export default function (module) { module.exports = {} }\n';
18
+ }
19
+ describe('_client/cjsHelpers loadDeps()', ({
20
+ it
21
+ }) => {
22
+ it(`loads a dependency cycle instead of hanging`, async () => {
23
+ const dir = await mkdtemp(join(tmpdir(), 'tungsten-load-deps-'));
24
+ try {
25
+ const a = pathToFileURL(join(dir, 'a.js')).href;
26
+ const b = pathToFileURL(join(dir, 'b.js')).href;
27
+ const c = pathToFileURL(join(dir, 'c.js')).href;
28
+ // a <-> b is circular, and both reach c
29
+ await writeFile(join(dir, 'a.js'), moduleSource([b, c]));
30
+ await writeFile(join(dir, 'b.js'), moduleSource([a, c]));
31
+ await writeFile(join(dir, 'c.js'), moduleSource([]));
32
+ const timeout = new Promise(resolve => setTimeout(() => resolve('timed out'), 5000).unref());
33
+ const loaded = await Promise.race([loadDeps([a]), timeout]);
34
+ expect(loaded).not.to.equal('timed out');
35
+ expect(Object.keys(loaded).sort()).to.deep.equal([a, b, c].sort());
36
+ } finally {
37
+ await rm(dir, {
38
+ recursive: true,
39
+ force: true
40
+ });
41
+ }
42
+ });
43
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"BabelTransformPackageImports.d.ts","sourceRoot":"","sources":["../../src/babelPlugins/BabelTransformPackageImports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BabelTransformPackageImports.d.ts","sourceRoot":"","sources":["../../src/babelPlugins/BabelTransformPackageImports.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,7 @@ import { frameworkDistFolder, packageName as frameworkPackageName, packageName,
27
27
  import { findProjectDir } from "../findProjectDir.js";
28
28
  import { cliError, cliWarn, cliNote, cliInfo, cliNews } from "../cliOutput.js";
29
29
  import { isBareImport } from "./isBareImport.js";
30
+ import { resolveBareImport } from "./transformPackageImports/resolveBareImport.js";
30
31
  import { TungstenError } from "../TungstenError.js";
31
32
  import { throwError } from "../throwError.js";
32
33
  //import { copyPackageModulesToPackagesFolder } from '../build/copyPackageModulesToPackagesFolder.js'
@@ -92,7 +93,11 @@ export function MakeBabelTransformPackageImports(opts) {
92
93
  try {
93
94
  const packageName = location.startsWith('@') ? location.split('/').slice(0, 2).join('/') : location.split('/')[0];
94
95
  const resolutionPaths = packageName === 'react' || packageName === 'react-dom' ? [opts.projectDir, sourcePackageDir] : [sourcePackageDir];
95
- fullLocation = require.resolve(location, {
96
+ // an import site resolves with the 'import' condition, a require()
97
+ // site with 'require' - see resolvePrecinctDependencies()
98
+ fullLocation = fileType === 'esm' ? resolveBareImport(location, resolutionPaths) ?? require.resolve(location, {
99
+ paths: resolutionPaths
100
+ }) : require.resolve(location, {
96
101
  paths: resolutionPaths
97
102
  });
98
103
  } catch (e) {
@@ -171,19 +176,24 @@ export function MakeBabelTransformPackageImports(opts) {
171
176
  history.push(`${error.dependency} (unresolved)`);
172
177
  return 'Your code that is compiled may depend on a node module - this is not allowed.' + `\nCould not resolve "${error.dependency}".` + `\nImport history:\n ${history.join('\n -> ')}`;
173
178
  }
174
- function resolvePrecinctDependencies(deps, file, sourceFilename, history) {
179
+ function resolvePrecinctDependencies(deps, file, fileType, sourceFilename, history) {
180
+ // Only a file that will be served as ESM may resolve with the 'import' condition.
181
+ // A converted CJS file's require() shim looks its dependencies up by the location
182
+ // recorded here, and the CJS transform resolves the same specifier with the
183
+ // 'require' condition - resolving the two differently loses the file.
184
+ const esmSource = fileType === 'esm';
175
185
  const out = [];
176
186
  for (const dep of deps) {
177
187
  if (dep.startsWith('node:')) continue;
178
188
  try {
179
189
  const packageName = dep.startsWith('@') ? dep.split('/').slice(0, 2).join('/') : dep.split('/')[0];
180
190
  if (packageName === 'react' || packageName === 'react-dom') {
181
- out.push(require.resolve(dep, {
191
+ out.push((esmSource ? resolveBareImport(dep, [opts.projectDir]) : undefined) ?? require.resolve(dep, {
182
192
  paths: [opts.projectDir]
183
193
  }));
184
194
  continue;
185
195
  }
186
- const f = getCjsRequire(file).resolve(dep);
196
+ const f = esmSource && isBareImport(dep) ? resolveBareImport(dep, [dirname(file)]) ?? getCjsRequire(file).resolve(dep) : getCjsRequire(file).resolve(dep);
187
197
  out.push(f);
188
198
  } catch (error) {
189
199
  throw new UnsupportedCompiledDependencyError(dep, file, history.length === 0 ? [sourceFilename] : history, {
@@ -204,7 +214,7 @@ export function MakeBabelTransformPackageImports(opts) {
204
214
  //console.log('getFileDependencies', 'd', d)
205
215
  return isBareImport(d) ? applyImportAliases(d, fileInfo.type) : d;
206
216
  });
207
- const resolved = resolvePrecinctDependencies(deps, file, sourceFilename, history);
217
+ const resolved = resolvePrecinctDependencies(deps, file, fileInfo.type, sourceFilename, history);
208
218
  return resolved;
209
219
  }
210
220
  function getFileEsmGenIntermediateCacheLocation(file, packageInfo) {
@@ -741,8 +751,10 @@ export function MakeBabelTransformPackageImports(opts) {
741
751
  //console.log(chalk.orange`We did the hacky jsx runtime alias in BabelTransformPackageImports`)
742
752
  location = 'tungsten/jsxRuntime.js';
743
753
  }
744
- // the real file location of the file being imported
745
- const importTarget = require.resolve(location);
754
+ // the real file location of the file being imported.
755
+ // User code is served as ESM, so it resolves with the 'import'
756
+ // condition - see resolvePrecinctDependencies()
757
+ const importTarget = resolveBareImport(location, [dirname(filename)]) ?? require.resolve(location);
746
758
  // Should do some checking here to show helpful errors about bad imports
747
759
  if (importTarget === location) {
748
760
  //console.log()
@@ -0,0 +1,2 @@
1
+ export declare function resolveBareImport(specifier: string, fromDirs: string[]): string | undefined;
2
+ //# sourceMappingURL=resolveBareImport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveBareImport.d.ts","sourceRoot":"","sources":["../../../src/babelPlugins/transformPackageImports/resolveBareImport.ts"],"names":[],"mappings":"AAcA,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAgB3F"}
@@ -0,0 +1,28 @@
1
+ import { join } from 'path';
2
+ import { fileURLToPath, pathToFileURL } from 'url';
3
+ import { moduleResolve } from 'import-meta-resolve';
4
+ // The conditions Node itself uses for `import`. Packages that ship both builds (zod, for
5
+ // example, has "import": "./index.js" and "require": "./index.cjs") then give us the ESM
6
+ // entry point, which the browser runs as-is instead of going through the CJS conversion.
7
+ const importConditions = new Set(['node', 'import']);
8
+ // Resolve a bare import the way `import` would, from any of the given directories.
9
+ // Returns undefined when the package cannot be resolved that way, so that the caller can
10
+ // fall back to require.resolve() - packages with no "exports" map, or with an "exports"
11
+ // map that only offers "require", still resolve through the CJS route.
12
+ export function resolveBareImport(specifier, fromDirs) {
13
+ for (const dir of fromDirs) {
14
+ // the base must name a file inside the directory, otherwise the node_modules walk
15
+ // starts at the directory's parent
16
+ const base = pathToFileURL(join(dir, '_'));
17
+ let resolved;
18
+ try {
19
+ resolved = moduleResolve(specifier, base, importConditions);
20
+ } catch {
21
+ continue;
22
+ }
23
+ // node: and data: URLs are not files we can copy to the browser
24
+ if (resolved.protocol !== 'file:') return undefined;
25
+ return fileURLToPath(resolved);
26
+ }
27
+ return undefined;
28
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolveBareImport.sxyt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveBareImport.sxyt.d.ts","sourceRoot":"","sources":["../../../src/babelPlugins/transformPackageImports/resolveBareImport.sxyt.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import { expect } from 'chai';
2
+ import { describe } from 'sxy-test-runner';
3
+ import { mkdir, mkdtemp, rm, writeFile } from 'fs/promises';
4
+ import { createRequire } from 'module';
5
+ import { tmpdir } from 'os';
6
+ import { join } from 'path';
7
+ import { resolveBareImport } from "./resolveBareImport.js";
8
+ async function makeFixture() {
9
+ const dir = await mkdtemp(join(tmpdir(), 'tungsten-resolve-bare-import-'));
10
+ const modules = join(dir, 'node_modules');
11
+ const dual = join(modules, 'dual-package');
12
+ await mkdir(dual, {
13
+ recursive: true
14
+ });
15
+ await writeFile(join(dual, 'package.json'), JSON.stringify({
16
+ name: 'dual-package',
17
+ version: '1.0.0',
18
+ exports: {
19
+ '.': {
20
+ import: './index.js',
21
+ require: './index.cjs'
22
+ }
23
+ }
24
+ }));
25
+ await writeFile(join(dual, 'index.js'), 'export default 1');
26
+ await writeFile(join(dual, 'index.cjs'), 'module.exports = 1');
27
+ const cjsOnly = join(modules, 'cjs-package');
28
+ await mkdir(cjsOnly, {
29
+ recursive: true
30
+ });
31
+ await writeFile(join(cjsOnly, 'package.json'), JSON.stringify({
32
+ name: 'cjs-package',
33
+ version: '1.0.0',
34
+ main: './main.js'
35
+ }));
36
+ await writeFile(join(cjsOnly, 'main.js'), 'module.exports = 1');
37
+ return {
38
+ dir,
39
+ dual,
40
+ cjsOnly
41
+ };
42
+ }
43
+ describe('resolveBareImport()', ({
44
+ it
45
+ }) => {
46
+ it(`takes the 'import' condition where require.resolve takes 'require'`, async () => {
47
+ const {
48
+ dir,
49
+ dual
50
+ } = await makeFixture();
51
+ try {
52
+ const require = createRequire(join(dir, '_'));
53
+ expect(require.resolve('dual-package')).to.equal(join(dual, 'index.cjs'));
54
+ expect(resolveBareImport('dual-package', [dir])).to.equal(join(dual, 'index.js'));
55
+ } finally {
56
+ await rm(dir, {
57
+ recursive: true,
58
+ force: true
59
+ });
60
+ }
61
+ });
62
+ it(`resolves a package that only has a legacy main`, async () => {
63
+ const {
64
+ dir,
65
+ cjsOnly
66
+ } = await makeFixture();
67
+ try {
68
+ expect(resolveBareImport('cjs-package', [dir])).to.equal(join(cjsOnly, 'main.js'));
69
+ } finally {
70
+ await rm(dir, {
71
+ recursive: true,
72
+ force: true
73
+ });
74
+ }
75
+ });
76
+ it(`returns undefined for a package it cannot resolve, so the caller can fall back`, async () => {
77
+ const {
78
+ dir
79
+ } = await makeFixture();
80
+ try {
81
+ expect(resolveBareImport('not-installed', [dir])).to.equal(undefined);
82
+ } finally {
83
+ await rm(dir, {
84
+ recursive: true,
85
+ force: true
86
+ });
87
+ }
88
+ });
89
+ it(`tries each of the given directories in turn`, async () => {
90
+ const {
91
+ dir,
92
+ dual
93
+ } = await makeFixture();
94
+ try {
95
+ const missing = join(dir, 'no-such-dir');
96
+ expect(resolveBareImport('dual-package', [missing, dir])).to.equal(join(dual, 'index.js'));
97
+ } finally {
98
+ await rm(dir, {
99
+ recursive: true,
100
+ force: true
101
+ });
102
+ }
103
+ });
104
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/bin/commands/compile.ts"],"names":[],"mappings":"AAyPA,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/bin/commands/compile.ts"],"names":[],"mappings":"AA+QA,OAAO,EAAE,CAAA"}
@@ -18,38 +18,58 @@ const targetOptions = {
18
18
  '--public': 'public'
19
19
  };
20
20
  const args = process.argv.slice(3);
21
- function optionValue(option) {
22
- const position = args.indexOf(option);
23
- if (position === -1) return undefined;
24
- const value = args[position + 1];
25
- if (value === undefined || value.startsWith('--')) {
26
- cliError(`${option} requires a path`);
27
- process.exit(1);
28
- }
29
- return value;
30
- }
21
+ const usage = 'Usage: tungsten compile [targets] [--all] [--watch] [--no-clean] [--output <dir>]';
31
22
  if (args.includes('--help') || args.includes('-h')) {
32
- cliOut('Usage: tungsten compile [targets] [--all] [--watch] [--no-clean] [--output <dir>]');
23
+ cliOut(usage);
33
24
  cliOut('Targets: --js, --css, --client, --assets, --public');
34
25
  cliOut('With no target options, all targets are compiled.');
35
26
  cliOut('Options: --output <dir>, --ready-file <file>, --quiet');
27
+ cliOut(' --ignore-dirs <dir>, --ignore-patterns <pattern>');
28
+ cliOut(' override the config entries of the same name. Repeat the option to');
29
+ cliOut(' give several values, or pass an empty value to ignore nothing.');
36
30
  process.exit(0);
37
31
  }
38
32
  const commandOptions = new Set(['--all', '--watch', '--no-clean', '--quiet']);
39
- const valueOptions = new Set(['--output', '--ready-file']);
40
- const optionValues = new Set();
41
- for (const option of valueOptions) {
42
- const position = args.indexOf(option);
43
- if (position !== -1 && args[position + 1] !== undefined) optionValues.add(args[position + 1]);
33
+ const valueOptions = new Set(['--output', '--ready-file', '--ignore-dirs', '--ignore-patterns']);
34
+ // values are collected per option so that the list options can be repeated
35
+ const givenOptionValues = new Map();
36
+ const unknownOptions = [];
37
+ let consumedPosition = -1;
38
+ for (const [position, arg] of args.entries()) {
39
+ if (position === consumedPosition) continue; // already taken as an option value
40
+ if (arg in targetOptions || commandOptions.has(arg)) continue;
41
+ if (valueOptions.has(arg)) {
42
+ const value = args[position + 1];
43
+ if (value === undefined || value.startsWith('--')) {
44
+ cliError(`${arg} requires a value`);
45
+ process.exit(1);
46
+ }
47
+ const values = givenOptionValues.get(arg);
48
+ if (values === undefined) givenOptionValues.set(arg, [value]);else values.push(value);
49
+ consumedPosition = position + 1;
50
+ } else {
51
+ unknownOptions.push(arg);
52
+ }
44
53
  }
45
- const unknownOptions = args.filter(arg => !(arg in targetOptions) && !commandOptions.has(arg) && !valueOptions.has(arg) && !optionValues.has(arg));
46
54
  if (unknownOptions.length > 0) {
47
55
  cliError(`Unknown compile option${unknownOptions.length === 1 ? '' : 's'}: ${unknownOptions.join(', ')}`);
48
- cliOut('Usage: tungsten compile [targets] [--all] [--watch] [--no-clean] [--output <dir>]');
56
+ cliOut(usage);
49
57
  process.exit(1);
50
58
  }
59
+ function optionValue(option) {
60
+ return givenOptionValues.get(option)?.at(-1);
61
+ }
62
+ // undefined leaves the config entry alone, '' clears it
63
+ function listOptionValue(option) {
64
+ const values = givenOptionValues.get(option);
65
+ if (values === undefined) return undefined;
66
+ const entries = values.filter(value => value !== '');
67
+ return entries.length === 0 ? '' : entries;
68
+ }
51
69
  const outputOption = optionValue('--output');
52
70
  const readyFileOption = optionValue('--ready-file');
71
+ const ignoreDirsOption = listOptionValue('--ignore-dirs');
72
+ const ignorePatternsOption = listOptionValue('--ignore-patterns');
53
73
  const requestedTargets = new Set();
54
74
  for (const arg of args) {
55
75
  const target = targetOptions[arg];
@@ -60,7 +80,14 @@ const watch = args.includes('--watch');
60
80
  const clean = !args.includes('--no-clean');
61
81
  const quiet = args.includes('--quiet');
62
82
  const projectDir = process.cwd();
63
- const config = await getUserConfig();
83
+ const config = await getUserConfig({
84
+ ...(ignoreDirsOption !== undefined ? {
85
+ ignoreDirs: ignoreDirsOption
86
+ } : {}),
87
+ ...(ignorePatternsOption !== undefined ? {
88
+ ignorePatterns: ignorePatternsOption
89
+ } : {})
90
+ });
64
91
  const codeLocation = join(projectDir, config.codeDir);
65
92
  const relSourceDir = config.sourceDir !== undefined && config.sourceDir !== '' ? config.sourceDir : config.codeDir;
66
93
  const sourceLocation = join(projectDir, relSourceDir);
@@ -117,10 +144,10 @@ if (targets.has('js')) {
117
144
  onCycleComplete: watch ? async cycle => {
118
145
  if (cycle.success) {
119
146
  await markReady();
120
- cliNews(`Compile cycle complete: js${cycle.file ? ` (${cycle.file})` : ''}`);
147
+ cliNews(`Compile cycle complete: js${cycle.file !== undefined ? ` (${cycle.file})` : ''}`);
121
148
  } else {
122
149
  await clearReadyFile();
123
- cliError(`Compile cycle failed: js${cycle.file ? ` (${cycle.file})` : ''}`);
150
+ cliError(`Compile cycle failed: js${cycle.file !== undefined ? ` (${cycle.file})` : ''}`);
124
151
  }
125
152
  } : undefined
126
153
  });
@@ -137,8 +164,8 @@ if (targets.has('client')) {
137
164
  compilationTasks.push(createClientFiles(config, 'dev', buildLocation));
138
165
  }
139
166
  if (targets.has('assets')) {
140
- const assetsTask = copyAssets(projectDir, config, buildLocation, watch);
141
- if (assetsTask !== undefined) compilationTasks.push(assetsTask);
167
+ // copyAssets resolves to undefined when there is no assets dir - nothing to skip here
168
+ compilationTasks.push(copyAssets(projectDir, config, buildLocation, watch));
142
169
  }
143
170
  if (targets.has('public')) {
144
171
  compilationTasks.push(copyPublicFiles(projectDir, config, buildLocation, watch));
@@ -94,6 +94,125 @@ describe('tungsten compile', ({
94
94
  });
95
95
  }
96
96
  });
97
+ it('takes the import build of a dual package for an import, and the require build for a require', async () => {
98
+ const projectDir = await mkdtemp(join(tmpdir(), 'tungsten-compile-conditions-test-'));
99
+ const cliLocation = join(findProjectDir(import.meta.url), 'dist', 'bin', 'index.js');
100
+ const sourceDir = join(projectDir, 'src');
101
+ const dualDir = join(projectDir, 'node_modules', 'dual-package');
102
+ const cjsDir = join(projectDir, 'node_modules', 'cjs-package');
103
+ async function copiedToPackages(rel) {
104
+ try {
105
+ await readFile(join(projectDir, '.tungsten/test/.packages', rel), 'utf8');
106
+ return true;
107
+ } catch {
108
+ return false;
109
+ }
110
+ }
111
+ try {
112
+ await mkdir(dualDir, {
113
+ recursive: true
114
+ });
115
+ await mkdir(cjsDir, {
116
+ recursive: true
117
+ });
118
+ await mkdir(sourceDir, {
119
+ recursive: true
120
+ });
121
+ await writeFile(join(projectDir, 'package.json'), '{"type":"module"}');
122
+ await writeFile(join(projectDir, 'tungsten.config.js'), 'export default { codeDir: "src", useRootComponent: false }');
123
+ // ships both builds, as @trpc/server and zod do
124
+ await writeFile(join(dualDir, 'package.json'), JSON.stringify({
125
+ name: 'dual-package',
126
+ version: '1.0.0',
127
+ exports: {
128
+ '.': {
129
+ import: './index.mjs',
130
+ require: './index.cjs'
131
+ }
132
+ }
133
+ }));
134
+ await writeFile(join(dualDir, 'index.mjs'), 'export const dual = "esm"');
135
+ await writeFile(join(dualDir, 'index.cjs'), 'module.exports = { dual: "cjs" }');
136
+ // a CJS package that require()s the dual package
137
+ await writeFile(join(cjsDir, 'package.json'), JSON.stringify({
138
+ name: 'cjs-package',
139
+ version: '1.0.0',
140
+ main: './index.js'
141
+ }));
142
+ await writeFile(join(cjsDir, 'index.js'), 'module.exports = require(\'dual-package\')');
143
+ await writeFile(join(sourceDir, 'entry.js'), 'import { dual } from \'dual-package\'\n' + 'import viaCjs from \'cjs-package\'\n' + 'export { dual, viaCjs }');
144
+ const {
145
+ stdout
146
+ } = await execFileAsync(process.execPath, [cliLocation, 'compile', '--js', '--output', '.tungsten/test', '--quiet'], {
147
+ cwd: projectDir
148
+ });
149
+ expect(stdout).to.contain('Compile complete');
150
+ // the ESM import took ./index.mjs
151
+ expect(await copiedToPackages('dual-package@1.0.0/index.mjs')).to.equal(true);
152
+ // and the require() inside the CJS package took ./index.cjs, so that the
153
+ // converted require() shim can find it in its deps
154
+ expect(await copiedToPackages('dual-package@1.0.0/index.cjs')).to.equal(true);
155
+ } finally {
156
+ await rm(projectDir, {
157
+ recursive: true,
158
+ force: true
159
+ });
160
+ }
161
+ });
162
+ it('overrides the ignoreDirs and ignorePatterns config entries from the command line', async () => {
163
+ const projectDir = await mkdtemp(join(tmpdir(), 'tungsten-compile-ignore-test-'));
164
+ const cliLocation = join(findProjectDir(import.meta.url), 'dist', 'bin', 'index.js');
165
+ const sourceDir = join(projectDir, 'src');
166
+ async function compiled(rel) {
167
+ try {
168
+ await readFile(join(projectDir, '.tungsten/test/code', rel), 'utf8');
169
+ return true;
170
+ } catch {
171
+ return false;
172
+ }
173
+ }
174
+ try {
175
+ await mkdir(join(sourceDir, 'server'), {
176
+ recursive: true
177
+ });
178
+ await mkdir(join(sourceDir, 'tests'), {
179
+ recursive: true
180
+ });
181
+ await writeFile(join(projectDir, 'package.json'), '{"type":"module"}');
182
+ await writeFile(join(projectDir, 'tungsten.config.js'), 'export default {' + ' codeDir: "src",' + ' useRootComponent: false,' + ' ignoreDirs: "server",' + ' ignorePatterns: "**/*.domTest.js"' + ' }');
183
+ await writeFile(join(sourceDir, 'entry.js'), 'export const entry = 1');
184
+ await writeFile(join(sourceDir, 'server', 'api.js'), 'export const api = 1');
185
+ await writeFile(join(sourceDir, 'tests', 'unit.js'), 'export const unit = 1');
186
+ await writeFile(join(sourceDir, 'component.domTest.js'), 'export const domTest = 1');
187
+ // the config entries alone - server/ and *.domTest.js are left out
188
+ await execFileAsync(process.execPath, [cliLocation, 'compile', '--js', '--output', '.tungsten/test', '--quiet'], {
189
+ cwd: projectDir
190
+ });
191
+ expect(await compiled('entry.js')).to.equal(true);
192
+ expect(await compiled('server/api.js')).to.equal(false);
193
+ expect(await compiled('component.domTest.js')).to.equal(false);
194
+ // blank values override both entries away, so everything is compiled
195
+ await execFileAsync(process.execPath, [cliLocation, 'compile', '--js', '--output', '.tungsten/test', '--quiet', '--ignore-dirs', '', '--ignore-patterns', ''], {
196
+ cwd: projectDir
197
+ });
198
+ expect(await compiled('server/api.js')).to.equal(true);
199
+ expect(await compiled('component.domTest.js')).to.equal(true);
200
+ // repeating an option replaces the config entry with all of the given values
201
+ await execFileAsync(process.execPath, [cliLocation, 'compile', '--js', '--output', '.tungsten/test', '--quiet', '--ignore-dirs', 'tests', '--ignore-dirs', 'server'], {
202
+ cwd: projectDir
203
+ });
204
+ expect(await compiled('entry.js')).to.equal(true);
205
+ expect(await compiled('tests/unit.js')).to.equal(false);
206
+ expect(await compiled('server/api.js')).to.equal(false);
207
+ // ignorePatterns was not overridden, so it still applies
208
+ expect(await compiled('component.domTest.js')).to.equal(false);
209
+ } finally {
210
+ await rm(projectDir, {
211
+ recursive: true,
212
+ force: true
213
+ });
214
+ }
215
+ });
97
216
  it('skips package compilation for files selected by a JavaScript glob', async () => {
98
217
  const projectDir = await mkdtemp(join(tmpdir(), 'tungsten-skip-package-compilation-test-'));
99
218
  const cliLocation = join(findProjectDir(import.meta.url), 'dist', 'bin', 'index.js');
@@ -1,3 +1,3 @@
1
- import { FrameworkConfigComplete } from './FrameworkConfig.js';
2
- export declare function getUserConfig(volume?: 'silent' | 'noisy'): Promise<FrameworkConfigComplete>;
1
+ import { FrameworkConfigComplete, FrameworkConfigOverrides } from './FrameworkConfig.js';
2
+ export declare function getUserConfig(overrides?: FrameworkConfigOverrides | null, volume?: 'silent' | 'noisy'): Promise<FrameworkConfigComplete>;
3
3
  //# sourceMappingURL=getUserConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getUserConfig.d.ts","sourceRoot":"","sources":["../src/getUserConfig.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAM9D,wBAAsB,aAAa,CAAC,MAAM,GAAE,QAAQ,GAAG,OAAiB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAyB1G"}
1
+ {"version":3,"file":"getUserConfig.d.ts","sourceRoot":"","sources":["../src/getUserConfig.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAMxF,wBAAsB,aAAa,CAC/B,SAAS,GAAE,wBAAwB,GAAG,IAAW,EACjD,MAAM,GAAE,QAAQ,GAAG,OAAiB,GACrC,OAAO,CAAC,uBAAuB,CAAC,CAyBlC"}
@@ -5,7 +5,7 @@ import { frameworkConfigValidator } from "./frameworkConfigSchema.js";
5
5
  import { makeFinalConfig } from "./makeFinalConfig.js";
6
6
  import { throwError } from "./throwError.js";
7
7
  import { cliOut } from "./cliOutput.js";
8
- export async function getUserConfig(volume = 'noisy') {
8
+ export async function getUserConfig(overrides = null, volume = 'noisy') {
9
9
  const userConfigOrNull = await findUserConfig(process.cwd(), volume);
10
10
  //frameworkCon
11
11
  if (userConfigOrNull !== null) {
@@ -15,11 +15,11 @@ export async function getUserConfig(volume = 'noisy') {
15
15
  cliOut('Config', userConfig);
16
16
  throwError('Your tungsten config did not match the required format', JSON.stringify(result.flatProblemsByPath));
17
17
  }
18
- const finalConfig = makeFinalConfig(result);
18
+ const finalConfig = makeFinalConfig(result, overrides);
19
19
  //console.log('finalConfig', finalConfig)
20
20
  return finalConfig;
21
21
  //return makeFinalConfig(userConfig.data)
22
22
  } else {
23
- return defaultConfig;
23
+ return makeFinalConfig(defaultConfig, overrides);
24
24
  }
25
25
  }
@@ -1,3 +1,3 @@
1
- import type { FrameworkConfig, FrameworkConfigComplete } from './FrameworkConfig.js';
2
- export declare function makeFinalConfig(userConfig: FrameworkConfig): FrameworkConfigComplete;
1
+ import type { FrameworkConfig, FrameworkConfigComplete, FrameworkConfigOverrides } from './FrameworkConfig.js';
2
+ export declare function makeFinalConfig(userConfig: FrameworkConfig, overrides?: FrameworkConfigOverrides | null): FrameworkConfigComplete;
3
3
  //# sourceMappingURL=makeFinalConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"makeFinalConfig.d.ts","sourceRoot":"","sources":["../src/makeFinalConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAGpF,wBAAgB,eAAe,CAAC,UAAU,EAAE,eAAe,GAAG,uBAAuB,CAUpF"}
1
+ {"version":3,"file":"makeFinalConfig.d.ts","sourceRoot":"","sources":["../src/makeFinalConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,eAAe,EAAE,uBAAuB,EAAE,wBAAwB,EACrE,MAAM,sBAAsB,CAAA;AAG7B,wBAAgB,eAAe,CAC3B,UAAU,EAAE,eAAe,EAC3B,SAAS,GAAE,wBAAwB,GAAG,IAAW,GAClD,uBAAuB,CAiBzB"}
@@ -1,10 +1,16 @@
1
1
  import { defaultConfig } from "./defaultConfig.js";
2
- export function makeFinalConfig(userConfig) {
2
+ export function makeFinalConfig(userConfig, overrides = null) {
3
3
  const finalConfig = structuredClone(defaultConfig);
4
4
  for (const key in userConfig) {
5
5
  //if (Object.prototype.hasOwnProperty.call(userConfig, key)) { // github co-pilot suggestion, unsure if needed
6
6
  finalConfig[key] = userConfig[key]; // eslint-disable-line no-type-assertion/no-type-assertion
7
7
  //}
8
8
  }
9
+ // an override left undefined keeps the user config / default value
10
+ for (const key in overrides) {
11
+ const value = overrides[key];
12
+ if (value === undefined) continue;
13
+ finalConfig[key] = value; // eslint-disable-line no-type-assertion/no-type-assertion
14
+ }
9
15
  return finalConfig;
10
16
  }
@@ -21,7 +21,7 @@ export function ensureTestEnvLoaded() {
21
21
  if (loadPromise === undefined) {
22
22
  loadPromise = (async () => {
23
23
  if (!testEnvIsRequested(process.env[testEnvVariableName])) return;
24
- const config = await getUserConfig('silent');
24
+ const config = await getUserConfig({}, 'silent');
25
25
  // iteration 0: schemas are stable within a test run.
26
26
  // _firstLoad = false: suppress the CLI boot output.
27
27
  // useTestEnvFiles = true: prefer .env.test* files.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tungsten",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {