@ryanatkn/gro 0.145.0 → 0.146.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.
@@ -1 +1 @@
1
- {"version":3,"file":"gro.config.default.d.ts","sourceRoot":"../src/lib/","sources":["gro.config.default.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AASvD;;;;;;;;GAQG;AACH,QAAA,MAAM,MAAM,EAAE,iBA4Bb,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"gro.config.default.d.ts","sourceRoot":"../src/lib/","sources":["gro.config.default.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAQvD;;;;;;;;GAQG;AACH,QAAA,MAAM,MAAM,EAAE,iBAwBb,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -3,8 +3,7 @@ import { has_server, gro_plugin_server } from './gro_plugin_server.js';
3
3
  import { gro_plugin_sveltekit_app } from './gro_plugin_sveltekit_app.js';
4
4
  import { has_sveltekit_app, has_sveltekit_library } from './sveltekit_helpers.js';
5
5
  import { gro_plugin_gen } from './gro_plugin_gen.js';
6
- import { gro_plugin_moss, has_moss_dep } from './gro_plugin_moss.js';
7
- import { load_package_json } from './package_json.js';
6
+ import { has_dep, load_package_json } from './package_json.js';
8
7
  /**
9
8
  * This is the default config that's passed to `gro.config.ts`
10
9
  * if it exists in the current project, and if not, this is the final config.
@@ -16,15 +15,15 @@ import { load_package_json } from './package_json.js';
16
15
  */
17
16
  const config = async (cfg) => {
18
17
  const package_json = load_package_json(); // TODO gets wastefully loaded by some plugins, maybe put in plugin/task context? how does that interact with `map_package_json`?
19
- const [moss_plugin_result, has_server_result, has_sveltekit_library_result, has_sveltekit_app_result,] = await Promise.all([
20
- has_moss_dep(package_json),
18
+ const [has_moss_dep, has_server_result, has_sveltekit_library_result, has_sveltekit_app_result] = await Promise.all([
19
+ has_dep('@ryanatkn/moss', package_json),
21
20
  has_server(),
22
21
  has_sveltekit_library(package_json),
23
22
  has_sveltekit_app(),
24
23
  ]);
25
- cfg.plugins = () => [
24
+ cfg.plugins = async () => [
26
25
  // put things that generate files before SvelteKit so it can see them
27
- moss_plugin_result.ok ? gro_plugin_moss() : null,
26
+ has_moss_dep ? (await import('./gro_plugin_moss.js')).gro_plugin_moss() : null, // lazy load to avoid errors if it's not installed
28
27
  gro_plugin_gen(),
29
28
  has_server_result.ok ? gro_plugin_server() : null,
30
29
  has_sveltekit_library_result.ok ? gro_plugin_sveltekit_library() : null,
@@ -1,22 +1,15 @@
1
- import type { Result } from '@ryanatkn/belt/result.js';
2
1
  import type { Plugin } from './plugin.js';
3
2
  import type { Args } from './args.js';
4
3
  import type { File_Filter } from './path.js';
5
- import { type Package_Json } from './package_json.js';
6
- export declare const MOSS_PACKAGE_DEP_NAME = "@ryanatkn/moss";
7
- export declare const has_moss_dep: (package_json: Package_Json, dep_name?: string) => Result<object, {
8
- message: string;
9
- }>;
10
- export declare const generate_classes_css: (classes: Iterable<string>) => string;
11
4
  export interface Task_Args extends Args {
12
5
  watch?: boolean;
13
6
  }
14
- export interface Options {
7
+ export interface Gro_Plugin_Moss_Options {
15
8
  include_classes?: string[] | Set<string> | null;
16
9
  outfile?: string;
17
10
  filter_file?: File_Filter | null;
18
11
  flush_debounce_delay?: number;
19
12
  banner?: string;
20
13
  }
21
- export declare const gro_plugin_moss: ({ include_classes, outfile, filter_file, flush_debounce_delay, banner, }?: Options) => Plugin;
14
+ export declare const gro_plugin_moss: ({ include_classes, outfile, filter_file, flush_debounce_delay, banner, }?: Gro_Plugin_Moss_Options) => Plugin;
22
15
  //# sourceMappingURL=gro_plugin_moss.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gro_plugin_moss.d.ts","sourceRoot":"../src/lib/","sources":["gro_plugin_moss.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,0BAA0B,CAAC;AAErD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAGpC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAU,KAAK,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAE7D,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,eAAO,MAAM,YAAY,iBACV,YAAY,wBAExB,MAAM,CAAC,MAAM,EAAE;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CASlC,CAAC;AAEF,eAAO,MAAM,oBAAoB,YAAa,QAAQ,CAAC,MAAM,CAAC,KAAG,MAmBhE,CAAC;AAIF,MAAM,WAAW,SAAU,SAAQ,IAAI;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACvB,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,8EAMzB,OAAO,KAAkB,MAmE3B,CAAC"}
1
+ {"version":3,"file":"gro_plugin_moss.d.ts","sourceRoot":"../src/lib/","sources":["gro_plugin_moss.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAGpC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,WAAW,CAAC;AAI3C,MAAM,WAAW,SAAU,SAAQ,IAAI;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACvC,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,8EAMzB,uBAAuB,KAAkB,MAmE3C,CAAC"}
@@ -2,40 +2,9 @@ import { EMPTY_OBJECT } from '@ryanatkn/belt/object.js';
2
2
  import { throttle } from '@ryanatkn/belt/throttle.js';
3
3
  import { Unreachable_Error } from '@ryanatkn/belt/error.js';
4
4
  import { writeFileSync } from 'node:fs';
5
- import { collect_css_classes, Css_Classes } from '@ryanatkn/moss/css_class_helpers.js';
5
+ import { collect_css_classes, Css_Classes, generate_classes_css, } from '@ryanatkn/moss/css_class_helpers.js';
6
6
  import { css_classes_by_name } from '@ryanatkn/moss/css_classes.js';
7
7
  import { format_file } from './format_file.js';
8
- import { has_dep } from './package_json.js';
9
- export const MOSS_PACKAGE_DEP_NAME = '@ryanatkn/moss';
10
- export const has_moss_dep = (package_json, dep_name = MOSS_PACKAGE_DEP_NAME) => {
11
- if (!has_dep(dep_name, package_json)) {
12
- return {
13
- ok: false,
14
- message: `no dependency found in package.json for ${dep_name}`,
15
- };
16
- }
17
- return { ok: true };
18
- };
19
- export const generate_classes_css = (classes) => {
20
- let css = '';
21
- for (const c of classes) {
22
- const v = css_classes_by_name[c];
23
- if (!v) {
24
- // diagnostic
25
- // if (!/^[a-z_0-9]+$/.test(c)) {
26
- // console.error('invalid class detected, fix the regexps', c);
27
- // }
28
- continue;
29
- }
30
- if ('declaration' in v) {
31
- css += `.${c} { ${v.declaration} }\n`;
32
- }
33
- else {
34
- css += v.ruleset + '\n';
35
- }
36
- }
37
- return css;
38
- };
39
8
  const FLUSH_DEBOUNCE_DELAY = 500;
40
9
  export const gro_plugin_moss = ({ include_classes = null, outfile = 'src/routes/moss.css', // TODO maybe support multiple files using file filters to check where to collect them?
41
10
  filter_file = (p) => !p.includes('.test.') && !p.includes('/test/'), flush_debounce_delay = FLUSH_DEBOUNCE_DELAY, banner = 'generated by gro_plugin_moss', } = EMPTY_OBJECT) => {
@@ -51,7 +20,7 @@ filter_file = (p) => !p.includes('.test.') && !p.includes('/test/'), flush_debou
51
20
  }
52
21
  };
53
22
  const flush_gen_queue = throttle(async () => {
54
- const css = generate_classes_css(css_classes.get_sorted_array());
23
+ const css = generate_classes_css(css_classes.get_sorted_array(), css_classes_by_name);
55
24
  const contents = `/* ${banner} */\n\n${css}\n\n/* ${banner} */`;
56
25
  const output = await format_file(contents, { filepath: outfile });
57
26
  // TODO think about using gen to implement this, would have some nice benefits like automatic change detection
package/dist/package.d.ts CHANGED
@@ -42,9 +42,9 @@ export declare const package_json: {
42
42
  '@ryanatkn/belt': string;
43
43
  chokidar: string;
44
44
  dotenv: string;
45
- 'es-module-lexer': string;
46
45
  'esm-env': string;
47
46
  mri: string;
47
+ 'oxc-parser': string;
48
48
  prettier: string;
49
49
  'prettier-plugin-svelte': string;
50
50
  'ts-morph': string;
@@ -742,13 +742,10 @@ export declare const src_json: {
742
742
  path: string;
743
743
  declarations: ({
744
744
  name: string;
745
- kind: "variable";
745
+ kind: "type";
746
746
  } | {
747
747
  name: string;
748
748
  kind: "function";
749
- } | {
750
- name: string;
751
- kind: "type";
752
749
  })[];
753
750
  };
754
751
  './gro_plugin_server.js': {
@@ -901,10 +898,10 @@ export declare const src_json: {
901
898
  path: string;
902
899
  declarations: ({
903
900
  name: string;
904
- kind: "function";
901
+ kind: "type";
905
902
  } | {
906
903
  name: string;
907
- kind: "type";
904
+ kind: "function";
908
905
  })[];
909
906
  };
910
907
  './path.js': {
@@ -1 +1 @@
1
- {"version":3,"file":"package.d.ts","sourceRoot":"../src/lib/","sources":["package.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuQD,CAAC;AAEzB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8wBD,CAAC"}
1
+ {"version":3,"file":"package.d.ts","sourceRoot":"../src/lib/","sources":["package.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuQD,CAAC;AAEzB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0wBD,CAAC"}
package/dist/package.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // generated by src/lib/package.gen.ts
2
2
  export const package_json = {
3
3
  name: '@ryanatkn/gro',
4
- version: '0.145.0',
4
+ version: '0.146.1',
5
5
  description: 'task runner and toolkit extending SvelteKit',
6
6
  motto: 'generate, run, optimize',
7
7
  glyph: '🌰',
@@ -42,9 +42,9 @@ export const package_json = {
42
42
  '@ryanatkn/belt': '^0.26.0',
43
43
  chokidar: '^4.0.1',
44
44
  dotenv: '^16.4.5',
45
- 'es-module-lexer': '^1.5.4',
46
45
  'esm-env': '^1.1.4',
47
46
  mri: '^1.2.0',
47
+ 'oxc-parser': '^0.34.0',
48
48
  prettier: '^3.3.3',
49
49
  'prettier-plugin-svelte': '^3.2.7',
50
50
  'ts-morph': '^24.0.0',
@@ -55,22 +55,22 @@ export const package_json = {
55
55
  devDependencies: {
56
56
  '@changesets/changelog-git': '^0.2.0',
57
57
  '@changesets/types': '^6.0.0',
58
- '@ryanatkn/eslint-config': '^0.5.5',
58
+ '@ryanatkn/eslint-config': '^0.5.6',
59
59
  '@ryanatkn/fuz': '^0.130.3',
60
- '@ryanatkn/moss': '^0.19.0',
60
+ '@ryanatkn/moss': '^0.20.0',
61
61
  '@sveltejs/adapter-static': '^3.0.6',
62
62
  '@sveltejs/kit': '^2.7.3',
63
63
  '@sveltejs/package': '^2.3.7',
64
64
  '@sveltejs/vite-plugin-svelte': '^4.0.0',
65
65
  '@types/fs-extra': '^11.0.4',
66
- '@types/node': '^22.8.4',
66
+ '@types/node': '^22.8.5',
67
67
  esbuild: '^0.21.5',
68
68
  eslint: '^9.13.0',
69
69
  'eslint-plugin-svelte': '^2.46.0',
70
- svelte: '^5.1.5',
70
+ svelte: '^5.1.6',
71
71
  'svelte-check': '^4.0.5',
72
72
  typescript: '^5.6.3',
73
- 'typescript-eslint': '^8.12.1',
73
+ 'typescript-eslint': '^8.12.2',
74
74
  uvu: '^0.5.6',
75
75
  },
76
76
  prettier: {
@@ -264,7 +264,7 @@ export const package_json = {
264
264
  };
265
265
  export const src_json = {
266
266
  name: '@ryanatkn/gro',
267
- version: '0.145.0',
267
+ version: '0.146.1',
268
268
  modules: {
269
269
  '.': {
270
270
  path: 'index.ts',
@@ -599,11 +599,8 @@ export const src_json = {
599
599
  './gro_plugin_moss.js': {
600
600
  path: 'gro_plugin_moss.ts',
601
601
  declarations: [
602
- { name: 'MOSS_PACKAGE_DEP_NAME', kind: 'variable' },
603
- { name: 'has_moss_dep', kind: 'function' },
604
- { name: 'generate_classes_css', kind: 'function' },
605
602
  { name: 'Task_Args', kind: 'type' },
606
- { name: 'Options', kind: 'type' },
603
+ { name: 'Gro_Plugin_Moss_Options', kind: 'type' },
607
604
  { name: 'gro_plugin_moss', kind: 'function' },
608
605
  ],
609
606
  },
@@ -743,7 +740,6 @@ export const src_json = {
743
740
  './parse_imports.js': {
744
741
  path: 'parse_imports.ts',
745
742
  declarations: [
746
- { name: 'init_lexer', kind: 'function' },
747
743
  { name: 'Import_Specifier', kind: 'type' },
748
744
  { name: 'parse_imports', kind: 'function' },
749
745
  ],
@@ -1,6 +1,5 @@
1
1
  import type { Flavored } from '@ryanatkn/belt/types.js';
2
2
  import type { Path_Id } from './path.js';
3
- export declare const init_lexer: () => Promise<void>;
4
3
  export type Import_Specifier = Flavored<string, 'Import_Specifier'>;
5
4
  export declare const parse_imports: (id: Path_Id, contents: string, ignore_types?: boolean) => Import_Specifier[];
6
5
  //# sourceMappingURL=parse_imports.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse_imports.d.ts","sourceRoot":"../src/lib/","sources":["parse_imports.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAIvC,eAAO,MAAM,UAAU,QAAO,OAAO,CAAC,IAAI,CAAS,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAIpE,eAAO,MAAM,aAAa,OACrB,OAAO,YACD,MAAM,6BAEd,gBAAgB,EA0BlB,CAAC"}
1
+ {"version":3,"file":"parse_imports.d.ts","sourceRoot":"../src/lib/","sources":["parse_imports.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAIvC,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAIpE,eAAO,MAAM,aAAa,OACrB,OAAO,YACD,MAAM,6BAEd,gBAAgB,EA4BlB,CAAC"}
@@ -1,13 +1,13 @@
1
- import { init, parse } from 'es-module-lexer';
1
+ import { moduleLexerSync } from 'oxc-parser';
2
2
  import { SVELTE_MATCHER } from './svelte_helpers.js';
3
3
  import { JS_MATCHER, TS_MATCHER } from './constants.js';
4
- export const init_lexer = () => init;
5
4
  const script_matcher = /<script.*?>(.*?)<\/script>/gimsu;
6
5
  export const parse_imports = (id, contents, ignore_types = true) => {
7
6
  const specifiers = [];
7
+ const is_svelte = SVELTE_MATCHER.test(id);
8
8
  const parse_from = (s) => {
9
- const parsed = parse(s);
10
- for (const p of parsed[0]) {
9
+ const parsed = moduleLexerSync(s, { sourceFilename: is_svelte ? id + '.ts' : id });
10
+ for (const p of parsed.imports) {
11
11
  if (ignore_types) {
12
12
  const import_statement = s.slice(p.ss, p.se);
13
13
  if (import_statement.startsWith('import type')) {
@@ -18,7 +18,7 @@ export const parse_imports = (id, contents, ignore_types = true) => {
18
18
  specifiers.push(p.n);
19
19
  }
20
20
  };
21
- if (SVELTE_MATCHER.test(id)) {
21
+ if (is_svelte) {
22
22
  const matches = contents.matchAll(script_matcher);
23
23
  for (const m of matches) {
24
24
  parse_from(m[1]);
@@ -1,6 +1,8 @@
1
1
  import { Package_Json } from './package_json.js';
2
2
  import type { Resolved_Specifier } from './resolve_specifier.js';
3
3
  /**
4
+ * Ideally Gro would just use `import.meta.resolve`, but it can't be used in custom loaders,
5
+ * which Gro relies on for TypeScript.
4
6
  * This likely has differences from Node - they should be fixed on a case-by-case basis.
5
7
  */
6
8
  export declare const resolve_node_specifier: (specifier: string, dir?: string, parent_path?: string, package_json_cache?: Record<string, Package_Json>, throw_on_missing_package?: boolean, exports_conditions?: string[]) => Resolved_Specifier | null;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve_node_specifier.d.ts","sourceRoot":"../src/lib/","sources":["resolve_node_specifier.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,YAAY,EAAoB,MAAM,mBAAmB,CAAC;AAGhF,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAG/D;;GAEG;AACH,eAAO,MAAM,sBAAsB,cACvB,MAAM,8BAEH,MAAM,uBACC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,wEAG/C,kBAAkB,GAAG,IA6FvB,CAAC"}
1
+ {"version":3,"file":"resolve_node_specifier.d.ts","sourceRoot":"../src/lib/","sources":["resolve_node_specifier.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,YAAY,EAAoB,MAAM,mBAAmB,CAAC;AAGhF,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,cACvB,MAAM,8BAEH,MAAM,uBACC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,wEAG/C,kBAAkB,GAAG,IAsFvB,CAAC"}
@@ -1,34 +1,25 @@
1
1
  import { join, extname } from 'node:path';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { DEV } from 'esm-env';
4
+ import { escape_regexp } from '@ryanatkn/belt/regexp.js';
4
5
  import { Export_Value, Package_Json, load_package_json } from './package_json.js';
5
6
  import { paths } from './paths.js';
6
7
  import { NODE_MODULES_DIRNAME } from './constants.js';
7
- import { escape_regexp } from '@ryanatkn/belt/regexp.js';
8
8
  /**
9
+ * Ideally Gro would just use `import.meta.resolve`, but it can't be used in custom loaders,
10
+ * which Gro relies on for TypeScript.
9
11
  * This likely has differences from Node - they should be fixed on a case-by-case basis.
10
12
  */
11
13
  export const resolve_node_specifier = (specifier, dir = paths.root, parent_path, package_json_cache, throw_on_missing_package = true, exports_conditions = DEV ? ['development', 'node', 'import'] : ['production', 'node', 'import']) => {
12
14
  const raw = specifier.endsWith('?raw');
13
15
  const mapped_specifier = raw ? specifier.substring(0, specifier.length - 4) : specifier;
14
- // Parse the specifier
15
- let idx = -1;
16
- if (mapped_specifier[0] === '@') {
17
- let count = 0;
18
- for (let i = 0; i < mapped_specifier.length; i++) {
19
- if (mapped_specifier[i] === '/')
20
- count++;
21
- if (count === 2) {
22
- idx = i;
23
- break;
24
- }
25
- }
26
- }
27
- else {
28
- idx = mapped_specifier.indexOf('/');
29
- }
30
- const pkg_name = idx === -1 ? mapped_specifier : mapped_specifier.substring(0, idx);
31
- const module_path = idx === -1 ? '' : mapped_specifier.substring(idx + 1);
16
+ const specifier_slash_path_index = get_specifier_slash_path_index(mapped_specifier);
17
+ const pkg_name = specifier_slash_path_index === -1
18
+ ? mapped_specifier
19
+ : mapped_specifier.substring(0, specifier_slash_path_index);
20
+ const module_path = specifier_slash_path_index === -1
21
+ ? ''
22
+ : mapped_specifier.substring(specifier_slash_path_index + 1);
32
23
  const subpath = module_path ? './' + module_path : '.';
33
24
  const package_dir = join(dir, NODE_MODULES_DIRNAME, pkg_name);
34
25
  // Check package_json cache first
@@ -117,6 +108,7 @@ const resolve_subpath = (package_json, subpath) => {
117
108
  if (subpath in exports) {
118
109
  return exports[subpath];
119
110
  }
111
+ // TODO some of this may be wrong, will just need to patch as we go
120
112
  // Sort patterns by specificity
121
113
  const patterns = Object.entries(exports)
122
114
  .filter(([pattern]) => pattern.includes('*'))
@@ -207,8 +199,7 @@ const resolve_exported_value = (exported, conditions) => {
207
199
  return undefined;
208
200
  }
209
201
  const exported_obj = exported;
210
- // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
211
- let default_value;
202
+ let default_value; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
212
203
  // For each key in exported_obj, in order
213
204
  for (const [condition, value] of Object.entries(exported_obj)) {
214
205
  // Skip invalid conditions
@@ -295,3 +286,21 @@ const validate_export_target = (target, throw_on_missing_package) => {
295
286
  }
296
287
  }
297
288
  };
289
+ const get_specifier_slash_path_index = (mapped_specifier) => {
290
+ let index = -1;
291
+ if (mapped_specifier[0] === '@') {
292
+ let count = 0;
293
+ for (let i = 0; i < mapped_specifier.length; i++) {
294
+ if (mapped_specifier[i] === '/')
295
+ count++;
296
+ if (count === 2) {
297
+ index = i;
298
+ break;
299
+ }
300
+ }
301
+ }
302
+ else {
303
+ index = mapped_specifier.indexOf('/');
304
+ }
305
+ return index;
306
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryanatkn/gro",
3
- "version": "0.145.0",
3
+ "version": "0.146.1",
4
4
  "description": "task runner and toolkit extending SvelteKit",
5
5
  "motto": "generate, run, optimize",
6
6
  "glyph": "🌰",
@@ -52,9 +52,9 @@
52
52
  "@ryanatkn/belt": "^0.26.0",
53
53
  "chokidar": "^4.0.1",
54
54
  "dotenv": "^16.4.5",
55
- "es-module-lexer": "^1.5.4",
56
55
  "esm-env": "^1.1.4",
57
56
  "mri": "^1.2.0",
57
+ "oxc-parser": "^0.34.0",
58
58
  "prettier": "^3.3.3",
59
59
  "prettier-plugin-svelte": "^3.2.7",
60
60
  "ts-morph": "^24.0.0",
@@ -68,22 +68,22 @@
68
68
  "devDependencies": {
69
69
  "@changesets/changelog-git": "^0.2.0",
70
70
  "@changesets/types": "^6.0.0",
71
- "@ryanatkn/eslint-config": "^0.5.5",
71
+ "@ryanatkn/eslint-config": "^0.5.6",
72
72
  "@ryanatkn/fuz": "^0.130.3",
73
- "@ryanatkn/moss": "^0.19.0",
73
+ "@ryanatkn/moss": "^0.20.0",
74
74
  "@sveltejs/adapter-static": "^3.0.6",
75
75
  "@sveltejs/kit": "^2.7.3",
76
76
  "@sveltejs/package": "^2.3.7",
77
77
  "@sveltejs/vite-plugin-svelte": "^4.0.0",
78
78
  "@types/fs-extra": "^11.0.4",
79
- "@types/node": "^22.8.4",
79
+ "@types/node": "^22.8.5",
80
80
  "esbuild": "^0.21.5",
81
81
  "eslint": "^9.13.0",
82
82
  "eslint-plugin-svelte": "^2.46.0",
83
- "svelte": "^5.1.5",
83
+ "svelte": "^5.1.6",
84
84
  "svelte-check": "^4.0.5",
85
85
  "typescript": "^5.6.3",
86
- "typescript-eslint": "^8.12.1",
86
+ "typescript-eslint": "^8.12.2",
87
87
  "uvu": "^0.5.6"
88
88
  },
89
89
  "prettier": {
@@ -4,8 +4,7 @@ import {has_server, gro_plugin_server} from './gro_plugin_server.js';
4
4
  import {gro_plugin_sveltekit_app} from './gro_plugin_sveltekit_app.js';
5
5
  import {has_sveltekit_app, has_sveltekit_library} from './sveltekit_helpers.js';
6
6
  import {gro_plugin_gen} from './gro_plugin_gen.js';
7
- import {gro_plugin_moss, has_moss_dep} from './gro_plugin_moss.js';
8
- import {load_package_json} from './package_json.js';
7
+ import {has_dep, load_package_json} from './package_json.js';
9
8
 
10
9
  /**
11
10
  * This is the default config that's passed to `gro.config.ts`
@@ -19,22 +18,18 @@ import {load_package_json} from './package_json.js';
19
18
  const config: Create_Gro_Config = async (cfg) => {
20
19
  const package_json = load_package_json(); // TODO gets wastefully loaded by some plugins, maybe put in plugin/task context? how does that interact with `map_package_json`?
21
20
 
22
- const [
23
- moss_plugin_result,
24
- has_server_result,
25
- has_sveltekit_library_result,
26
- has_sveltekit_app_result,
27
- ] = await Promise.all([
28
- has_moss_dep(package_json),
29
- has_server(),
30
- has_sveltekit_library(package_json),
31
- has_sveltekit_app(),
32
- ]);
21
+ const [has_moss_dep, has_server_result, has_sveltekit_library_result, has_sveltekit_app_result] =
22
+ await Promise.all([
23
+ has_dep('@ryanatkn/moss', package_json),
24
+ has_server(),
25
+ has_sveltekit_library(package_json),
26
+ has_sveltekit_app(),
27
+ ]);
33
28
 
34
- cfg.plugins = () =>
29
+ cfg.plugins = async () =>
35
30
  [
36
31
  // put things that generate files before SvelteKit so it can see them
37
- moss_plugin_result.ok ? gro_plugin_moss() : null,
32
+ has_moss_dep ? (await import('./gro_plugin_moss.js')).gro_plugin_moss() : null, // lazy load to avoid errors if it's not installed
38
33
  gro_plugin_gen(),
39
34
  has_server_result.ok ? gro_plugin_server() : null,
40
35
  has_sveltekit_library_result.ok ? gro_plugin_sveltekit_library() : null,
@@ -2,53 +2,18 @@ import {EMPTY_OBJECT} from '@ryanatkn/belt/object.js';
2
2
  import {throttle} from '@ryanatkn/belt/throttle.js';
3
3
  import {Unreachable_Error} from '@ryanatkn/belt/error.js';
4
4
  import {writeFileSync} from 'node:fs';
5
- import {collect_css_classes, Css_Classes} from '@ryanatkn/moss/css_class_helpers.js';
5
+ import {
6
+ collect_css_classes,
7
+ Css_Classes,
8
+ generate_classes_css,
9
+ } from '@ryanatkn/moss/css_class_helpers.js';
6
10
  import {css_classes_by_name} from '@ryanatkn/moss/css_classes.js';
7
- import type {Result} from '@ryanatkn/belt/result.js';
8
11
 
9
12
  import type {Plugin} from './plugin.js';
10
13
  import type {Args} from './args.js';
11
14
  import type {Cleanup_Watch} from './filer.js';
12
15
  import {format_file} from './format_file.js';
13
16
  import type {File_Filter} from './path.js';
14
- import {has_dep, type Package_Json} from './package_json.js';
15
-
16
- export const MOSS_PACKAGE_DEP_NAME = '@ryanatkn/moss';
17
-
18
- export const has_moss_dep = (
19
- package_json: Package_Json,
20
- dep_name = MOSS_PACKAGE_DEP_NAME,
21
- ): Result<object, {message: string}> => {
22
- if (!has_dep(dep_name, package_json)) {
23
- return {
24
- ok: false,
25
- message: `no dependency found in package.json for ${dep_name}`,
26
- };
27
- }
28
-
29
- return {ok: true};
30
- };
31
-
32
- export const generate_classes_css = (classes: Iterable<string>): string => {
33
- let css = '';
34
- for (const c of classes) {
35
- const v = css_classes_by_name[c];
36
- if (!v) {
37
- // diagnostic
38
- // if (!/^[a-z_0-9]+$/.test(c)) {
39
- // console.error('invalid class detected, fix the regexps', c);
40
- // }
41
- continue;
42
- }
43
- if ('declaration' in v) {
44
- css += `.${c} { ${v.declaration} }\n`;
45
- } else {
46
- css += v.ruleset + '\n';
47
- }
48
- }
49
-
50
- return css;
51
- };
52
17
 
53
18
  const FLUSH_DEBOUNCE_DELAY = 500;
54
19
 
@@ -56,7 +21,7 @@ export interface Task_Args extends Args {
56
21
  watch?: boolean;
57
22
  }
58
23
 
59
- export interface Options {
24
+ export interface Gro_Plugin_Moss_Options {
60
25
  include_classes?: string[] | Set<string> | null;
61
26
  outfile?: string;
62
27
  filter_file?: File_Filter | null;
@@ -70,7 +35,7 @@ export const gro_plugin_moss = ({
70
35
  filter_file = (p) => !p.includes('.test.') && !p.includes('/test/'),
71
36
  flush_debounce_delay = FLUSH_DEBOUNCE_DELAY,
72
37
  banner = 'generated by gro_plugin_moss',
73
- }: Options = EMPTY_OBJECT): Plugin => {
38
+ }: Gro_Plugin_Moss_Options = EMPTY_OBJECT): Plugin => {
74
39
  const css_classes = new Css_Classes(
75
40
  Array.isArray(include_classes) ? new Set(include_classes) : include_classes,
76
41
  );
@@ -88,7 +53,7 @@ export const gro_plugin_moss = ({
88
53
  };
89
54
  const flush_gen_queue = throttle(
90
55
  async () => {
91
- const css = generate_classes_css(css_classes.get_sorted_array());
56
+ const css = generate_classes_css(css_classes.get_sorted_array(), css_classes_by_name);
92
57
  const contents = `/* ${banner} */\n\n${css}\n\n/* ${banner} */`;
93
58
  const output = await format_file(contents, {filepath: outfile});
94
59
  // TODO think about using gen to implement this, would have some nice benefits like automatic change detection
@@ -5,7 +5,7 @@ import type {Src_Json} from './src_json.js';
5
5
 
6
6
  export const package_json = {
7
7
  name: '@ryanatkn/gro',
8
- version: '0.145.0',
8
+ version: '0.146.1',
9
9
  description: 'task runner and toolkit extending SvelteKit',
10
10
  motto: 'generate, run, optimize',
11
11
  glyph: '🌰',
@@ -47,9 +47,9 @@ export const package_json = {
47
47
  '@ryanatkn/belt': '^0.26.0',
48
48
  chokidar: '^4.0.1',
49
49
  dotenv: '^16.4.5',
50
- 'es-module-lexer': '^1.5.4',
51
50
  'esm-env': '^1.1.4',
52
51
  mri: '^1.2.0',
52
+ 'oxc-parser': '^0.34.0',
53
53
  prettier: '^3.3.3',
54
54
  'prettier-plugin-svelte': '^3.2.7',
55
55
  'ts-morph': '^24.0.0',
@@ -60,22 +60,22 @@ export const package_json = {
60
60
  devDependencies: {
61
61
  '@changesets/changelog-git': '^0.2.0',
62
62
  '@changesets/types': '^6.0.0',
63
- '@ryanatkn/eslint-config': '^0.5.5',
63
+ '@ryanatkn/eslint-config': '^0.5.6',
64
64
  '@ryanatkn/fuz': '^0.130.3',
65
- '@ryanatkn/moss': '^0.19.0',
65
+ '@ryanatkn/moss': '^0.20.0',
66
66
  '@sveltejs/adapter-static': '^3.0.6',
67
67
  '@sveltejs/kit': '^2.7.3',
68
68
  '@sveltejs/package': '^2.3.7',
69
69
  '@sveltejs/vite-plugin-svelte': '^4.0.0',
70
70
  '@types/fs-extra': '^11.0.4',
71
- '@types/node': '^22.8.4',
71
+ '@types/node': '^22.8.5',
72
72
  esbuild: '^0.21.5',
73
73
  eslint: '^9.13.0',
74
74
  'eslint-plugin-svelte': '^2.46.0',
75
- svelte: '^5.1.5',
75
+ svelte: '^5.1.6',
76
76
  'svelte-check': '^4.0.5',
77
77
  typescript: '^5.6.3',
78
- 'typescript-eslint': '^8.12.1',
78
+ 'typescript-eslint': '^8.12.2',
79
79
  uvu: '^0.5.6',
80
80
  },
81
81
  prettier: {
@@ -270,7 +270,7 @@ export const package_json = {
270
270
 
271
271
  export const src_json = {
272
272
  name: '@ryanatkn/gro',
273
- version: '0.145.0',
273
+ version: '0.146.1',
274
274
  modules: {
275
275
  '.': {
276
276
  path: 'index.ts',
@@ -605,11 +605,8 @@ export const src_json = {
605
605
  './gro_plugin_moss.js': {
606
606
  path: 'gro_plugin_moss.ts',
607
607
  declarations: [
608
- {name: 'MOSS_PACKAGE_DEP_NAME', kind: 'variable'},
609
- {name: 'has_moss_dep', kind: 'function'},
610
- {name: 'generate_classes_css', kind: 'function'},
611
608
  {name: 'Task_Args', kind: 'type'},
612
- {name: 'Options', kind: 'type'},
609
+ {name: 'Gro_Plugin_Moss_Options', kind: 'type'},
613
610
  {name: 'gro_plugin_moss', kind: 'function'},
614
611
  ],
615
612
  },
@@ -749,7 +746,6 @@ export const src_json = {
749
746
  './parse_imports.js': {
750
747
  path: 'parse_imports.ts',
751
748
  declarations: [
752
- {name: 'init_lexer', kind: 'function'},
753
749
  {name: 'Import_Specifier', kind: 'type'},
754
750
  {name: 'parse_imports', kind: 'function'},
755
751
  ],
@@ -1,12 +1,10 @@
1
- import {init, parse} from 'es-module-lexer';
1
+ import {moduleLexerSync} from 'oxc-parser';
2
2
  import type {Flavored} from '@ryanatkn/belt/types.js';
3
3
 
4
4
  import type {Path_Id} from './path.js';
5
5
  import {SVELTE_MATCHER} from './svelte_helpers.js';
6
6
  import {JS_MATCHER, TS_MATCHER} from './constants.js';
7
7
 
8
- export const init_lexer = (): Promise<void> => init;
9
-
10
8
  export type Import_Specifier = Flavored<string, 'Import_Specifier'>;
11
9
 
12
10
  const script_matcher = /<script.*?>(.*?)<\/script>/gimsu;
@@ -18,9 +16,11 @@ export const parse_imports = (
18
16
  ): Import_Specifier[] => {
19
17
  const specifiers: string[] = [];
20
18
 
19
+ const is_svelte = SVELTE_MATCHER.test(id);
20
+
21
21
  const parse_from = (s: string): void => {
22
- const parsed = parse(s);
23
- for (const p of parsed[0]) {
22
+ const parsed = moduleLexerSync(s, {sourceFilename: is_svelte ? id + '.ts' : id});
23
+ for (const p of parsed.imports) {
24
24
  if (ignore_types) {
25
25
  const import_statement = s.slice(p.ss, p.se);
26
26
  if (import_statement.startsWith('import type')) {
@@ -31,7 +31,7 @@ export const parse_imports = (
31
31
  }
32
32
  };
33
33
 
34
- if (SVELTE_MATCHER.test(id)) {
34
+ if (is_svelte) {
35
35
  const matches = contents.matchAll(script_matcher);
36
36
  for (const m of matches) {
37
37
  parse_from(m[1]);
@@ -1,14 +1,16 @@
1
1
  import {join, extname} from 'node:path';
2
2
  import {existsSync} from 'node:fs';
3
3
  import {DEV} from 'esm-env';
4
+ import {escape_regexp} from '@ryanatkn/belt/regexp.js';
4
5
 
5
6
  import {Export_Value, Package_Json, load_package_json} from './package_json.js';
6
7
  import {paths} from './paths.js';
7
8
  import {NODE_MODULES_DIRNAME} from './constants.js';
8
9
  import type {Resolved_Specifier} from './resolve_specifier.js';
9
- import {escape_regexp} from '@ryanatkn/belt/regexp.js';
10
10
 
11
11
  /**
12
+ * Ideally Gro would just use `import.meta.resolve`, but it can't be used in custom loaders,
13
+ * which Gro relies on for TypeScript.
12
14
  * This likely has differences from Node - they should be fixed on a case-by-case basis.
13
15
  */
14
16
  export const resolve_node_specifier = (
@@ -22,23 +24,16 @@ export const resolve_node_specifier = (
22
24
  const raw = specifier.endsWith('?raw');
23
25
  const mapped_specifier = raw ? specifier.substring(0, specifier.length - 4) : specifier;
24
26
 
25
- // Parse the specifier
26
- let idx: number = -1;
27
- if (mapped_specifier[0] === '@') {
28
- let count = 0;
29
- for (let i = 0; i < mapped_specifier.length; i++) {
30
- if (mapped_specifier[i] === '/') count++;
31
- if (count === 2) {
32
- idx = i;
33
- break;
34
- }
35
- }
36
- } else {
37
- idx = mapped_specifier.indexOf('/');
38
- }
27
+ const specifier_slash_path_index = get_specifier_slash_path_index(mapped_specifier);
39
28
 
40
- const pkg_name = idx === -1 ? mapped_specifier : mapped_specifier.substring(0, idx);
41
- const module_path = idx === -1 ? '' : mapped_specifier.substring(idx + 1);
29
+ const pkg_name =
30
+ specifier_slash_path_index === -1
31
+ ? mapped_specifier
32
+ : mapped_specifier.substring(0, specifier_slash_path_index);
33
+ const module_path =
34
+ specifier_slash_path_index === -1
35
+ ? ''
36
+ : mapped_specifier.substring(specifier_slash_path_index + 1);
42
37
  const subpath = module_path ? './' + module_path : '.';
43
38
  const package_dir = join(dir, NODE_MODULES_DIRNAME, pkg_name);
44
39
 
@@ -144,6 +139,7 @@ const resolve_subpath = (package_json: Package_Json, subpath: string): unknown =
144
139
  return exports[subpath];
145
140
  }
146
141
 
142
+ // TODO some of this may be wrong, will just need to patch as we go
147
143
  // Sort patterns by specificity
148
144
  const patterns = Object.entries(exports)
149
145
  .filter(([pattern]) => pattern.includes('*'))
@@ -255,8 +251,7 @@ const resolve_exported_value = (
255
251
 
256
252
  const exported_obj = exported as Record<string, unknown>;
257
253
 
258
- // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
259
- let default_value: Export_Value | undefined;
254
+ let default_value: Export_Value | undefined; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents
260
255
 
261
256
  // For each key in exported_obj, in order
262
257
  for (const [condition, value] of Object.entries(exported_obj)) {
@@ -354,3 +349,21 @@ const validate_export_target = (target: string, throw_on_missing_package: boolea
354
349
  }
355
350
  }
356
351
  };
352
+
353
+ const get_specifier_slash_path_index = (mapped_specifier: string): number => {
354
+ let index: number = -1;
355
+ if (mapped_specifier[0] === '@') {
356
+ let count = 0;
357
+ for (let i = 0; i < mapped_specifier.length; i++) {
358
+ if (mapped_specifier[i] === '/') count++;
359
+ if (count === 2) {
360
+ index = i;
361
+ break;
362
+ }
363
+ }
364
+ } else {
365
+ index = mapped_specifier.indexOf('/');
366
+ }
367
+
368
+ return index;
369
+ };