pinstripe 0.9.0 → 0.12.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.
Files changed (131) hide show
  1. package/README.md +1 -1
  2. package/cli.js +5 -7
  3. package/lib/async_path_builder.js +4 -0
  4. package/lib/async_path_builder.test.js +11 -0
  5. package/lib/base.js +13 -2
  6. package/lib/base.test.js +30 -28
  7. package/lib/client.js +49 -0
  8. package/lib/command.js +20 -0
  9. package/lib/commands/_importer.js +2 -0
  10. package/lib/commands/create_database.js +1 -3
  11. package/lib/commands/drop_database.js +1 -3
  12. package/lib/commands/generate_command.js +10 -8
  13. package/lib/commands/generate_migration.js +10 -8
  14. package/lib/commands/generate_model.js +11 -9
  15. package/lib/commands/generate_node_wrapper.js +36 -0
  16. package/lib/commands/generate_project.js +2 -11
  17. package/lib/commands/generate_service.js +10 -8
  18. package/lib/commands/generate_static_site.js +79 -0
  19. package/lib/commands/generate_view.js +6 -8
  20. package/lib/commands/init_database.js +2 -4
  21. package/lib/commands/list_commands.js +2 -3
  22. package/lib/commands/list_migrations.js +2 -3
  23. package/lib/commands/list_models.js +2 -3
  24. package/lib/commands/list_node_wrappers.js +14 -0
  25. package/lib/commands/list_services.js +2 -3
  26. package/lib/commands/list_views.js +2 -3
  27. package/lib/commands/migrate_database.js +1 -3
  28. package/lib/commands/reset_database.js +2 -4
  29. package/lib/commands/seed_database.js +2 -4
  30. package/lib/commands/start_console.js +2 -3
  31. package/lib/commands/start_server.js +17 -10
  32. package/lib/constants.js +0 -9
  33. package/lib/css.js +101 -0
  34. package/lib/database/adapter.js +23 -0
  35. package/lib/database/adapters/mysql.js +629 -0
  36. package/lib/database/adapters/sqlite.js +590 -0
  37. package/lib/database/column.js +8 -48
  38. package/lib/database/constants.js +25 -44
  39. package/lib/database/migration.js +20 -0
  40. package/lib/database/migrator.js +6 -3
  41. package/lib/database/row.js +152 -96
  42. package/lib/database/sql.js +47 -44
  43. package/lib/database/sql.test.js +58 -0
  44. package/lib/database/table.js +77 -202
  45. package/lib/database/union.js +21 -39
  46. package/lib/database.js +30 -121
  47. package/lib/environment.js +4 -2
  48. package/lib/html.js +1 -1
  49. package/lib/import_all.js +22 -9
  50. package/lib/index.js +7 -8
  51. package/lib/initialize.client.js +3 -3
  52. package/lib/migrations/1627976184_create_user.js +2 -4
  53. package/lib/migrations/1628057822_create_session.js +2 -4
  54. package/lib/migrations/_importer.js +2 -0
  55. package/lib/models/_importer.js +2 -0
  56. package/lib/models/session.js +2 -4
  57. package/lib/models/user.js +4 -5
  58. package/lib/node_wrapper.js +242 -26
  59. package/lib/node_wrappers/_importer.js +2 -0
  60. package/lib/node_wrappers/anchor.client.js +18 -0
  61. package/lib/{widgets → node_wrappers}/document.client.js +12 -19
  62. package/lib/node_wrappers/form.client.js +16 -0
  63. package/lib/{widgets → node_wrappers}/frame.client.js +32 -11
  64. package/lib/node_wrappers/helpers.js +48 -0
  65. package/lib/node_wrappers/markdown_editor/line_inserter.client.js +14 -0
  66. package/lib/node_wrappers/markdown_editor.client.js +34 -0
  67. package/lib/node_wrappers/overlay.client.js +26 -0
  68. package/lib/{widgets/document → node_wrappers}/progress_bar.client.js +7 -6
  69. package/lib/overload.js +1 -0
  70. package/lib/service_factory.js +40 -0
  71. package/lib/services/_importer.js +2 -0
  72. package/lib/services/args.js +1 -4
  73. package/lib/services/cli_utils.js +2 -4
  74. package/lib/services/config.js +19 -8
  75. package/lib/services/cookies.js +2 -4
  76. package/lib/services/database.js +2 -5
  77. package/lib/services/fetch.js +33 -23
  78. package/lib/services/fork_environment.js +2 -4
  79. package/lib/services/fs_builder.js +2 -3
  80. package/lib/services/params.js +1 -4
  81. package/lib/services/project.js +1 -3
  82. package/lib/services/read_file.js +6 -0
  83. package/lib/services/render_css.js +6 -0
  84. package/lib/services/render_file.js +4 -7
  85. package/lib/services/render_form.js +108 -66
  86. package/lib/services/render_html.js +2 -4
  87. package/lib/services/render_list.js +58 -0
  88. package/lib/services/render_markdown.js +44 -0
  89. package/lib/services/render_table.js +67 -0
  90. package/lib/services/render_view.js +7 -18
  91. package/lib/services/reset_environment.js +2 -4
  92. package/lib/services/run_command.js +2 -4
  93. package/lib/services/session.js +2 -4
  94. package/lib/services/theme_config.js +76 -0
  95. package/lib/services/view.js +4 -0
  96. package/lib/thatify.js +1 -1
  97. package/lib/url.js +12 -4
  98. package/lib/url.test.js +5 -1
  99. package/lib/validatable.js +1 -5
  100. package/lib/view.js +109 -2
  101. package/lib/views/_importer.js +2 -0
  102. package/lib/views/{layout.js → _layout.js} +13 -17
  103. package/lib/views/base.css.js +657 -0
  104. package/lib/views/blocks/default.js +25 -0
  105. package/lib/views/blocks/help.js +139 -0
  106. package/lib/views/bundle.js.js +36 -0
  107. package/lib/{controllers → views}/sign_in.js +5 -4
  108. package/lib/views/sign_out.js +15 -0
  109. package/lib/virtual_node.js +41 -46
  110. package/package.json +10 -14
  111. package/babel.config.cjs +0 -12
  112. package/lib/commands/generate_controller.js +0 -33
  113. package/lib/commands/generate_widget.js +0 -30
  114. package/lib/commands/list_controllers.js +0 -15
  115. package/lib/commands/list_widgets.js +0 -15
  116. package/lib/controller.js +0 -19
  117. package/lib/controllers/bundle.js +0 -62
  118. package/lib/controllers/sign_out.js +0 -15
  119. package/lib/renderable.js +0 -25
  120. package/lib/scss/index.scss +0 -2
  121. package/lib/services/render_controller.js +0 -11
  122. package/lib/services/render_script.js +0 -14
  123. package/lib/static/bundle.css +0 -10308
  124. package/lib/static/bundle.css.map +0 -1
  125. package/lib/widgets/anchor.client.js +0 -54
  126. package/lib/widgets/document/style.client.js +0 -49
  127. package/lib/widgets/form.client.js +0 -61
  128. package/lib/widgets/input.client.js +0 -23
  129. package/lib/widgets/overlay.client.js +0 -27
  130. package/lib/widgets/script.client.js +0 -9
  131. package/pinstripe.scss +0 -2
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  ## What is Pinstripe?
5
5
 
6
- Pinstripe is a fullstack JavaScript web framework for Node.js and the browser that follows the [model-view-controller (MVC)](https://en.wikipedia.org/wiki/Model-view-controller) design pattern.
6
+ Pinstripe is a fullstack JavaScript web framework for Node.js.
7
7
 
8
8
  ## License
9
9
 
package/cli.js CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  import { spawn } from 'child_process';
4
4
 
5
- import { importAll } from './lib/import_all.js';
6
5
  import { project } from './lib/project.js';
7
6
  import { Command } from './lib/command.js';
8
- import { Environment } from './lib/environment.js';
7
+ import { createEnvironment } from './lib/environment.js';
9
8
 
10
9
  (async () => {
11
10
  const { entryPath, localPinstripePath, exists } = await project;
@@ -18,12 +17,12 @@ import { Environment } from './lib/environment.js';
18
17
  stdio: 'inherit'
19
18
  });
20
19
  } else {
21
- await importAll();
22
20
  if(entryPath){
23
- await import(entryPath);
24
- await importAll();
21
+ import(entryPath);
25
22
  }
26
23
 
24
+ const { runCommand, resetEnvironment } = await createEnvironment();
25
+
27
26
  if(exists){
28
27
  Command.unregister('generate-project');
29
28
  } else {
@@ -34,8 +33,7 @@ import { Environment } from './lib/environment.js';
34
33
  }
35
34
  });
36
35
  }
37
-
38
- const { runCommand, resetEnvironment } = Environment.new();
36
+
39
37
  try {
40
38
  await runCommand(...args);
41
39
  } catch(e) {
@@ -15,6 +15,10 @@ export const AsyncPathBuilder = Base.extend().include({
15
15
  return new this.constructor(this._startObject, [...this._path, args ]);
16
16
  },
17
17
 
18
+ get toString(){
19
+ return this.__getMissing('toString');
20
+ },
21
+
18
22
  then(...args){
19
23
  return unwrap(this._startObject, [...this._path]).then(...args);
20
24
  }
@@ -25,3 +25,14 @@ test('AsyncPathBuilder (2)', async () => {
25
25
  expect(await foo.bar().baz()).toBe("boo");
26
26
  expect(await foo.bar().baz().length).toBe(3);
27
27
  });
28
+
29
+ test('AsyncPathBuilder (3)', async () => {
30
+ const foo = AsyncPathBuilder.new({
31
+ toString(){
32
+ return "hello world";
33
+ }
34
+ });
35
+
36
+ expect(await foo.toString()).toBe("hello world");
37
+ });
38
+
package/lib/base.js CHANGED
@@ -86,6 +86,13 @@ export class Base {
86
86
  traps.ownKeys = () => {
87
87
  return this.__keys();
88
88
  };
89
+
90
+ traps.getOwnPropertyDescriptor = (target, prop) => {
91
+ return {
92
+ enumerable: true,
93
+ configurable: true,
94
+ };
95
+ }
89
96
  }
90
97
 
91
98
  if(Object.keys(traps).length){
@@ -110,17 +117,21 @@ const assignProps = (target, ...sources) => {
110
117
  return;
111
118
  }
112
119
  const descriptor = { ...Object.getOwnPropertyDescriptor(source, name) };
113
- const { get } = descriptor;
120
+ const { get, set } = descriptor;
121
+ const { get: targetGet, set: targetSet } = (Object.getOwnPropertyDescriptor(target, name) || {});
114
122
  if(get){
115
123
  descriptor.get = function(...args){
116
124
  return get.call(this.__proxy || this, ...args);
117
125
  };
126
+ } else if(targetGet) {
127
+ descriptor.get = targetGet;
118
128
  }
119
- const { set } = descriptor;
120
129
  if(set){
121
130
  descriptor.set = function(...args){
122
131
  set.call(this.__proxy || this, ...args);
123
132
  };
133
+ } else if(targetSet){
134
+ descriptor.set = targetSet;
124
135
  }
125
136
  Object.defineProperty(target, name, descriptor);
126
137
  });
package/lib/base.test.js CHANGED
@@ -65,32 +65,34 @@ test(`Base - if the __call has been defined getting/setting still works`, async
65
65
  }).new();
66
66
 
67
67
  expect(fixture.foo).toBe("bar");
68
- })
68
+ });
69
+
70
+ test(`Base - can produce dynamic keys`, () => {
71
+ const fixture = Base.extend().include({
72
+ baz: 'hello world',
73
+
74
+ __keys(){
75
+ return ['foo', 'bar'];
76
+ }
77
+ }).new();
78
+
79
+ expect(Object.keys(fixture)).toEqual(['foo', 'bar']);
80
+ });
69
81
 
70
- // test(`Base - classes can be included in other classes`, () => {
71
- // const Foo = Base.extend().include({
72
- // fruit(){
73
- // return 'apple';
74
- // }
75
- // });
76
- // const Bar = Base.extend().include(Foo);
77
-
78
- // expect(Foo.new().fruit()).toBe('apple');
79
- // expect(Bar.new().fruit()).toBe('apple');
80
- // });
81
-
82
- // test(`Base - abstract classes can be included in other classes`, () => {
83
- // const Foo = Base.extend().include({
84
- // abstract: true,
85
-
86
- // fruit(){
87
- // return 'apple';
88
- // }
89
- // });
90
- // const Bar = Base.extend().include(Foo);
91
- // const Baz = Base.extend().include(Bar);
92
-
93
- // expect(typeof Foo.new().fruit).toBe('undefined');
94
- // expect(Bar.new().fruit()).toBe('apple');
95
- // expect(Baz.new().fruit()).toBe('apple');
96
- // });
82
+ test(`Base - getters and setters with same name can be defined independently`, () => {
83
+ const fixture = Base.extend().include({
84
+ meta(){
85
+ this.prototype.assignProps({
86
+ get foo(){
87
+ return 'bar';
88
+ }
89
+ });
90
+ },
91
+
92
+ set foo(value){
93
+
94
+ }
95
+ }).new();
96
+
97
+ expect(fixture.foo).toEqual('bar');
98
+ })
package/lib/client.js ADDED
@@ -0,0 +1,49 @@
1
+
2
+ import { promisify } from 'util';
3
+ import { readFile } from 'fs';
4
+ import { Volume as MemFs } from 'memfs';
5
+ import * as fs from 'fs';
6
+ import { Union as UnionFs } from 'unionfs';
7
+
8
+ import { Base } from './base.js';
9
+ import { overload } from './overload.js';
10
+
11
+ export const client = Base.extend().include({
12
+ initialize(){
13
+ this.files = {};
14
+ },
15
+
16
+ addFile: overload({
17
+ ['string, function'](filePath, fn){
18
+ this.files[filePath] = fn;
19
+ },
20
+
21
+ string(filePath){
22
+ this.addFile(filePath, async () => {
23
+ return (await promisify(readFile)(filePath)).toString();
24
+ });
25
+ },
26
+ }),
27
+
28
+ async createFs(entryFilePath){
29
+ const files = {};
30
+ const filePaths = Object.keys(this.files);
31
+ while(filePaths.length){
32
+ const filePath = filePaths.pop();
33
+ const data = await this.files[filePath]();
34
+ files[filePath] = data.replace(/(.*)\/\/\s*pinstripe-if-client:\s*(.*)/g, '$2 // pinstripe-if-server: $1');
35
+ }
36
+ return new UnionFs().use(fs).use(new MemFs.fromJSON({
37
+ ...files,
38
+ [entryFilePath]: `
39
+ ${
40
+ Object.keys(this.files).filter(filePath => filePath.match(/\/[^\.\/]+(\.client\.js)$/)).map(filePath => `
41
+ import ${JSON.stringify(filePath)};
42
+ `).join('\n')
43
+ }
44
+ `
45
+ }));
46
+ }
47
+ }).new();
48
+
49
+ export const addFileToClient = (...args) => client.addFile(...args);
package/lib/command.js CHANGED
@@ -4,6 +4,7 @@ import { Registrable } from './registrable.js';
4
4
  import { dasherize } from './inflector.js';
5
5
  import { overload } from './overload.js';
6
6
  import { thatify } from './thatify.js';
7
+ import { addFileToClient } from './client.js';
7
8
 
8
9
  export const Command = Base.extend().include({
9
10
  meta(){
@@ -47,3 +48,22 @@ export const defineCommand = overload({
47
48
  defineCommand(name, { run: thatify(fn) });
48
49
  }
49
50
  });
51
+
52
+ export const commandImporter = dirPath => {
53
+ return async filePath => {
54
+ const relativeFilePath = filePath.substr(dirPath.length).replace(/^\//, '');
55
+
56
+ if(filePath.match(/\.js$/)){
57
+ const relativeFilePathWithoutExtension = relativeFilePath.replace(/\.[^/]+$/, '');
58
+ if(relativeFilePathWithoutExtension == '_importer'){
59
+ return;
60
+ }
61
+ addFileToClient(filePath);
62
+ const definition = await ( await import(filePath) ).default;
63
+ if(definition !== undefined){
64
+ defineCommand(relativeFilePathWithoutExtension, definition);
65
+ }
66
+ return;
67
+ }
68
+ };
69
+ };
@@ -0,0 +1,2 @@
1
+
2
+ export { commandImporter as default } from 'pinstripe';
@@ -1,4 +1,2 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('create-database', ({ database }) => database.create());
2
+ export default ({ database }) => database.create();
@@ -1,4 +1,2 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('drop-database', ({ database }) => database.drop());
2
+ export default ({ database }) => database.drop();
@@ -1,7 +1,5 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('generate-command', async ({
2
+ export default async ({
5
3
  cliUtils: { extractArg },
6
4
  fsBuilder: { inProjectRootDir, generateFile, line, indent },
7
5
  snakeify, dasherize
@@ -14,17 +12,21 @@ defineCommand('generate-command', async ({
14
12
 
15
13
  await inProjectRootDir(async () => {
16
14
 
17
- await generateFile(`lib/commands/${name}.js`, () => {
15
+ await generateFile(`lib/commands/_importer.js`, { skipIfExists: true }, () => {
16
+ line();
17
+ line(`export { commandImporter as default } from 'pinstripe';`);
18
18
  line();
19
- line(`import { defineCommand } from 'pinstripe';`);
19
+ });
20
+
21
+ await generateFile(`lib/commands/${name}.js`, () => {
20
22
  line();
21
- line(`defineCommand('${dasherize(name)}', () => {`);
23
+ line(`export default () => {`);
22
24
  indent(() => {
23
25
  line(`console.log('${dasherize(name)} command coming soon!')`);
24
26
  });
25
- line('});');
27
+ line('};');
26
28
  line();
27
29
  });
28
30
 
29
31
  });
30
- });
32
+ };
@@ -1,7 +1,5 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('generate-migration', async ({
2
+ export default async ({
5
3
  cliUtils: { extractArg, extractFields, extractOptions },
6
4
  fsBuilder: { inProjectRootDir, generateFile, line, indent },
7
5
  snakeify
@@ -22,11 +20,15 @@ defineCommand('generate-migration', async ({
22
20
 
23
21
  await inProjectRootDir(async () => {
24
22
 
25
- await generateFile(`lib/migrations/${name}.js`, () => {
23
+ await generateFile(`lib/migrations/_importer.js`, { skipIfExists: true }, () => {
24
+ line();
25
+ line(`export { migrationImporter as default } from 'pinstripe';`);
26
26
  line();
27
- line(`import { defineMigration } from 'pinstripe';`);
27
+ });
28
+
29
+ await generateFile(`lib/migrations/${name}.js`, () => {
28
30
  line();
29
- line(`defineMigration('${name}', async ({ database }) => {`);
31
+ line(`export default async ({ database }) => {`);
30
32
  indent(() => {
31
33
  line();
32
34
  if(table && fields.length){
@@ -36,8 +38,8 @@ defineCommand('generate-migration', async ({
36
38
  line();
37
39
  }
38
40
  })
39
- line('});');
41
+ line('};');
40
42
  line();
41
43
  });
42
44
  });
43
- });
45
+ };
@@ -1,7 +1,5 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('generate-model', async ({
2
+ export default async ({
5
3
  cliUtils: { extractArg, extractFields },
6
4
  fsBuilder: { inProjectRootDir, generateFile, line, indent },
7
5
  snakeify, pluralize, camelize,
@@ -17,7 +15,7 @@ defineCommand('generate-model', async ({
17
15
  const fields = extractFields();
18
16
 
19
17
  const collectionName = camelize(pluralize(name));
20
- if(!await database[collectionName].exists){
18
+ if(!await database[collectionName].exists()){
21
19
  const denormalizedFields = fields.map(({ mandatory, name, type }) => {
22
20
  return `${ mandatory ? '^' : '' }${name}:${type}`
23
21
  });
@@ -26,17 +24,21 @@ defineCommand('generate-model', async ({
26
24
 
27
25
  await inProjectRootDir(async () => {
28
26
 
29
- await generateFile(`lib/models/${name}.js`, () => {
27
+ await generateFile(`lib/models/_importer.js`, { skipIfExists: true }, () => {
28
+ line();
29
+ line(`export { modelImporter as default } from 'pinstripe';`);
30
30
  line();
31
- line(`import { defineModel } from 'pinstripe';`);
31
+ });
32
+
33
+ await generateFile(`lib/models/${name}.js`, () => {
32
34
  line();
33
- line(`defineModel('${name}', {`);
35
+ line(`export default {`);
34
36
  indent(() => {
35
37
  line();
36
38
  });
37
- line('});');
39
+ line('};');
38
40
  line();
39
41
  });
40
42
 
41
43
  });
42
- });
44
+ };
@@ -0,0 +1,36 @@
1
+
2
+ export default async ({
3
+ cliUtils: { extractArg },
4
+ fsBuilder: { inProjectRootDir, generateFile, line, indent },
5
+ snakeify
6
+ }) => {
7
+ const name = snakeify(extractArg(''));
8
+ if(name == ''){
9
+ console.error('A node wrapper name must be given.');
10
+ process.exit();
11
+ }
12
+
13
+ await inProjectRootDir(async () => {
14
+
15
+ await generateFile(`lib/node_wrappers/_importer.js`, { skipIfExists: true }, () => {
16
+ line();
17
+ line(`export { nodeWrapperImporter as default } from 'pinstripe';`);
18
+ line();
19
+ });
20
+
21
+ await generateFile(`lib/node_wrappers/${name}.client.js`, () => {
22
+ line();
23
+ line(`export default {`);
24
+ indent(() => {
25
+ line(`initialize(){`);
26
+ indent(() => {
27
+ line(`this.constructor.parent.prototype.initialize.call(this, ...args);`);
28
+ });
29
+ line(`}`);
30
+ });
31
+ line('};');
32
+ line();
33
+ });
34
+
35
+ });
36
+ };
@@ -1,9 +1,7 @@
1
1
 
2
2
  import { spawnSync } from 'child_process';
3
3
 
4
- import { defineCommand } from 'pinstripe';
5
-
6
- defineCommand('generate-project', async ({
4
+ export default async ({
7
5
  cliUtils: { extractArg, extractOptions },
8
6
  fsBuilder: { generateDir, generateFile, line, indent, echo }
9
7
  }) => {
@@ -43,16 +41,9 @@ defineCommand('generate-project', async ({
43
41
  line();
44
42
  });
45
43
 
46
- await generateFile(`lib/web/_importer.js`, () => {
47
- line();
48
- line(`export { webImporter as default } from 'pinstripe';`);
49
- line();
50
- });
51
-
52
-
53
44
  spawnSync('yarn', [ 'add', ...dependencies ], {
54
45
  stdio: 'inherit'
55
46
  });
56
47
 
57
48
  });
58
- });
49
+ };
@@ -1,7 +1,5 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('generate-service', async ({
2
+ export default async ({
5
3
  cliUtils: { extractArg },
6
4
  fsBuilder: { inProjectRootDir, generateFile, line, indent },
7
5
  snakeify, camelize
@@ -14,17 +12,21 @@ defineCommand('generate-service', async ({
14
12
 
15
13
  await inProjectRootDir(async () => {
16
14
 
17
- await generateFile(`lib/services/${snakeify(name)}.js`, () => {
15
+ await generateFile(`lib/services/_importer.js`, { skipIfExists: true }, () => {
16
+ line();
17
+ line(`export { serviceImporter as default } from 'pinstripe';`);
18
18
  line();
19
- line(`import { defineService } from 'pinstripe';`);
19
+ });
20
+
21
+ await generateFile(`lib/services/${snakeify(name)}.js`, () => {
20
22
  line();
21
- line(`defineService('${camelize(name)}', () => {`);
23
+ line(`export default () => {`);
22
24
  indent(() => {
23
25
  line(`return 'Example ${camelize(name)} service'`);
24
26
  });
25
- line('});');
27
+ line('};');
26
28
  line();
27
29
  });
28
30
 
29
31
  });
30
- });
32
+ };
@@ -0,0 +1,79 @@
1
+
2
+ import { VirtualNode } from '../virtual_node.js';
3
+ import { Url } from '../url.js';
4
+ import { View } from '../view.js';
5
+ import { default as mimeTypes } from 'mime-types';
6
+
7
+ export default {
8
+
9
+ async run(){
10
+ this.pages = {};
11
+ const paths = Object.keys(View.classes).filter(path => !path.match(/(^|\/)_/)).map(path => {
12
+ return `/${path.replace(/(^|\/)index$/, '')}`.replace(/^\/+/, '/');
13
+ });
14
+
15
+ while(paths.length){
16
+ await this.crawlPage({ _path: paths.shift() });
17
+ }
18
+
19
+ const pages = Object.values(this.pages).filter(page => page.status == 200 && Object.keys(page.params).length == 1);
20
+ const { inProjectRootDir, generateDir, generateFile, echo } = this.fsBuilder;
21
+
22
+ await inProjectRootDir(async () => {
23
+ await generateDir('build/static', async () => {
24
+ while(pages.length){
25
+ const { params, headers } = pages.shift();
26
+ const contentType = headers['content-type'];
27
+
28
+ const path = params._path;
29
+ let filePath = path.replace(/^\//, '');
30
+ if(filePath.match(/(^|\/)$/)){
31
+ filePath = `${filePath}index`;
32
+ }
33
+ if(!filePath.match(/[^/]+\.[^/]+$/)){
34
+ filePath = `${filePath}.${mimeTypes.extension(contentType)}`
35
+ }
36
+
37
+ const data = (await this.fetch({ _path: path }))[2];
38
+
39
+ await generateFile(filePath, () => {
40
+ echo(data.join(''));
41
+ });
42
+ }
43
+ });
44
+ });
45
+ },
46
+
47
+ async crawlPage(params){
48
+ const hash = JSON.stringify(params);
49
+ if(this.pages[hash]) return;
50
+ const page = { params };
51
+ this.pages[hash] = page;
52
+ const [ status, headers, data ] = await this.fetch(params);
53
+ page.status = status;
54
+ page.headers = headers;
55
+ if(status != 200 || headers['content-type'] != 'text/html') return;
56
+ const html = data.join('');
57
+ const virtualDom = VirtualNode.fromString(html);
58
+ const urls = this.extractUrls(virtualDom);
59
+ while(urls.length){
60
+ const url = urls.shift();
61
+ await this.crawlPage({ ...url.params, _path: url.path });
62
+ }
63
+ },
64
+
65
+ extractUrls(virtualDom){
66
+ const out = [];
67
+ virtualDom.traverse(({ attributes }) => {
68
+ ['src', 'href'].forEach(name => {
69
+ const value = attributes[name];
70
+ if(!value) return;
71
+ const url = Url.fromString(value, 'http://localhost/');
72
+ if(url.host != 'localhost') return;
73
+ out.push(url);
74
+ });
75
+ });
76
+ return out;
77
+ }
78
+
79
+ };
@@ -1,7 +1,5 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('generate-view', async ({
2
+ export default async ({
5
3
  cliUtils: { extractArg },
6
4
  fsBuilder: { inProjectRootDir, generateFile, line, indent }
7
5
  }) => {
@@ -16,14 +14,14 @@ defineCommand('generate-view', async ({
16
14
  }
17
15
 
18
16
  await inProjectRootDir(async () => {
19
-
20
- await generateFile(`lib/web/_importer.js`, { skipIfExists: true }, () => {
17
+
18
+ await generateFile(`lib/views/_importer.js`, { skipIfExists: true }, () => {
21
19
  line();
22
- line(`export { webImporter as default } from 'pinstripe';`);
20
+ line(`export { viewImporter as default } from 'pinstripe';`);
23
21
  line();
24
22
  });
25
23
 
26
- await generateFile(`lib/web/${name}`, () => {
24
+ await generateFile(`lib/views/${name}`, () => {
27
25
  line();
28
26
  line('export default ({ renderHtml, params }) => renderHtml(`');
29
27
  indent(() => {
@@ -33,4 +31,4 @@ defineCommand('generate-view', async ({
33
31
  line();
34
32
  });
35
33
  });
36
- });
34
+ };
@@ -1,8 +1,6 @@
1
1
 
2
- import { defineCommand } from 'pinstripe';
3
-
4
- defineCommand('init-database', async ({ runCommand }) => {
2
+ export default async ({ runCommand }) => {
5
3
  await runCommand('create-database');
6
4
  await runCommand('migrate-database');
7
5
  await runCommand('seed-database');
8
- });
6
+ };
@@ -1,10 +1,9 @@
1
1
 
2
2
  import chalk from 'chalk';
3
- import { defineCommand } from 'pinstripe';
4
3
 
5
4
  import { Command } from '../command.js';
6
5
 
7
- defineCommand('list-commands', () => {
6
+ export default () => {
8
7
  console.log('');
9
8
  console.log('The following commands are available:');
10
9
  console.log('');
@@ -12,4 +11,4 @@ defineCommand('list-commands', () => {
12
11
  console.log(` * ${chalk.green(commandName)}`);
13
12
  });
14
13
  console.log('');
15
- });
14
+ };
@@ -1,10 +1,9 @@
1
1
 
2
2
  import chalk from 'chalk';
3
- import { defineCommand } from 'pinstripe';
4
3
 
5
4
  import { Migration } from '../database/migration.js'
6
5
 
7
- defineCommand('list-migrations', () => {
6
+ export default () => {
8
7
  console.log('');
9
8
  console.log('The following migrations are available:');
10
9
  console.log('');
@@ -12,4 +11,4 @@ defineCommand('list-migrations', () => {
12
11
  console.log(` * ${chalk.green(migrationName)}`);
13
12
  });
14
13
  console.log('');
15
- });
14
+ };